<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jay Barker</title>
    <description>The latest articles on DEV Community by Jay Barker (@jaybarker).</description>
    <link>https://dev.to/jaybarker</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3517117%2Ff15639e8-7359-4295-aaee-a51c1d47a6b5.png</url>
      <title>DEV Community: Jay Barker</title>
      <link>https://dev.to/jaybarker</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jaybarker"/>
    <language>en</language>
    <item>
      <title>Local SEO Basics for Service Businesses</title>
      <dc:creator>Jay Barker</dc:creator>
      <pubDate>Sat, 24 Oct 2026 22:48:00 +0000</pubDate>
      <link>https://dev.to/jaybarker/local-seo-basics-for-service-businesses-58cm</link>
      <guid>https://dev.to/jaybarker/local-seo-basics-for-service-businesses-58cm</guid>
      <description>&lt;p&gt;You build a fast, clean, beautiful website for a local plumber. Lighthouse scores in the 90s, proper headings, a tidy contact form. You launch it, hand over the keys and move on. Three months later, the plumber emails you: "We're still not showing up on the map when people search for plumbers in town."&lt;/p&gt;

&lt;p&gt;The site wasn't the problem, or at least not the whole problem. Local SEO for small business is about half Google Business Profile, which lives entirely outside your codebase, and half website details that developers rarely think about until something goes wrong.&lt;/p&gt;

&lt;p&gt;This guide is for developers and freelancers who build sites for local service businesses (plumbers, electricians, salons, cleaners, contractors) and for technical owners doing it themselves. I'll cover how local rankings actually work, the Business Profile rules that affect your build, site architecture that doesn't trip Google's spam policies, treating business details as code, LocalBusiness structured data, the conversion details local customers need, reviews and measurement.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; I work with the teams behind Nexi Bloom and SEO Site Checker, both mentioned below. Everything else here is based on Google's own documentation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Short Version
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google ranks local results mainly on relevance, distance and prominence.&lt;/strong&gt; You can't pay for better local rankings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Google Business Profile drives the map results.&lt;/strong&gt; The website supports it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build one strong page per core service,&lt;/strong&gt; and only create location pages that have genuinely local content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the business name, address and phone number (NAP) in one source of truth&lt;/strong&gt; in your code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add accurate LocalBusiness structured data,&lt;/strong&gt; and tag the profile's website link so you can measure what it brings in.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How Local Search Actually Works
&lt;/h2&gt;

&lt;p&gt;When someone searches "plumber near me" or "emergency plumber Westfield," Google usually shows two kinds of results. First comes the &lt;strong&gt;map pack&lt;/strong&gt;, a map with three businesses, powered by Google Business Profile. Below it are the &lt;strong&gt;local organic results&lt;/strong&gt;, regular web pages ranked partly on location relevance. Your website mostly competes in the second, and supports the first.&lt;/p&gt;

&lt;p&gt;Google is unusually open about how the map results work. &lt;a href="https://support.google.com/business/answer/7091" rel="noopener noreferrer"&gt;Google's guide to improving local ranking&lt;/a&gt; says local results are "mainly based on relevance, distance, and popularity":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Relevance&lt;/strong&gt; is how well a Business Profile matches the search. Complete, detailed information helps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distance&lt;/strong&gt; is how far the business is from the searcher, or from the location in the search.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prominence&lt;/strong&gt; is how well known the business is, including signals like links from other websites and reviews.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two things follow from this. First, distance is the one factor nobody can change, which is why a business can't rank in the map pack across an entire metro area just by having a great website. Second, Google states plainly that "There's no way to request or pay for a better local ranking on Google." So be wary of anyone who promises otherwise, and set your clients' expectations accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Google Business Profile: The Part You Can't Code
&lt;/h2&gt;

&lt;p&gt;You won't write any code for the Business Profile, but its setup affects how you build the site, so it's worth understanding. The essentials are verification, an accurate primary category (the strongest relevance signal), relevant secondary categories, hours, services, attributes and plenty of real photos.&lt;/p&gt;

&lt;p&gt;Service businesses have extra rules. Under &lt;a href="https://support.google.com/business/answer/9157481" rel="noopener noreferrer"&gt;Google's service-area business guidelines&lt;/a&gt;, if customers aren't served at the business address, the address should be hidden on the profile. A service-area business can list up to 20 service areas, defined by cities, postal codes or other areas rather than a radius, and the overall area shouldn't extend beyond about two hours' drive from the business. Each service-area business gets one profile covering the whole area.&lt;/p&gt;

&lt;p&gt;The business name on the profile should be the real business name, without extra keywords stuffed in. "Westfield Plumbing Co." is fine. "Westfield Plumbing Co. | Best 24/7 Emergency Plumber Drain Cleaning" isn't.&lt;/p&gt;

&lt;p&gt;Here's the part that &lt;em&gt;is&lt;/em&gt; your job. The profile has a website link, and by default, clicks from it are hard to separate from other Google traffic in analytics. Tag it with UTM parameters so you can measure it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://westfieldplumbing.example/?utm_source=google&amp;amp;utm_medium=organic&amp;amp;utm_campaign=gbp_listing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure the page still has a canonical tag pointing to the clean URL, so the parameters don't create duplicates in search.&lt;/p&gt;

&lt;h2&gt;
  
  
  Site Architecture for Service Businesses
&lt;/h2&gt;

&lt;h3&gt;
  
  
  One strong page per core service
&lt;/h3&gt;

&lt;p&gt;A single "Services" page that lists eight services in a paragraph each won't rank for any of them. Each core service the business wants customers for should have its own page with real substance: what's included, how it works, typical timing, rough pricing guidance where the client is comfortable sharing it, photos of real jobs and answers to common questions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Location pages, without creating doorway pages
&lt;/h3&gt;

&lt;p&gt;Service-area pages ("Plumbing in Cranford," "Plumbing in Scotch Plains") can help, but this is where many local sites get into trouble. &lt;a href="https://developers.google.com/search/docs/essentials/spam-policies" rel="noopener noreferrer"&gt;Google's spam policies&lt;/a&gt; describe doorway abuse, and one of their examples is "pages targeted at specific regions or cities that funnel users to one page." Ten near-identical pages with the town name swapped are exactly that.&lt;/p&gt;

&lt;p&gt;So only create a location page when there's something genuinely local to say: jobs completed in that area, local specifics (older homes with particular plumbing, local permit requirements), area-specific FAQs, reviews from customers there and directions or coverage details. If you can't write that content, don't create the page. A strong service page that mentions the areas served is better than a dozen thin ones.&lt;/p&gt;

&lt;h3&gt;
  
  
  URL structure and internal linking
&lt;/h3&gt;

&lt;p&gt;Keep the structure simple and predictable. A small plumbing business might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/
├── /services/
│   ├── /services/drain-cleaning
│   ├── /services/water-heater-repair
│   └── /services/emergency-plumbing
├── /areas/
│   ├── /areas/westfield
│   └── /areas/cranford
├── /about
├── /reviews
└── /contact
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Link service pages to the relevant area pages and back, add breadcrumbs, and make sure every important page is reachable within a couple of clicks of the homepage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Businesses with more than one location
&lt;/h3&gt;

&lt;p&gt;If the business has multiple physical locations that customers visit, each one needs its own page, with its own address, phone number, hours and structured data. Don't merge them into one page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treat NAP as a Single Source of Truth
&lt;/h2&gt;

&lt;p&gt;Consistency of the business name, address and phone number across the Business Profile, the website and directories matters for local SEO. On the website, the most common way consistency breaks is depressingly simple: the phone number is hardcoded in the header, the footer, the contact page and the schema, and when it changes, someone updates three of the four.&lt;/p&gt;

&lt;p&gt;Put it in one config file and import it everywhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// config/business.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;business&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Westfield Plumbing Co.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Plumber&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://westfieldplumbing.example&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;(555) 555-0142&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;e164&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;+15555550142&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;street&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;12 Main Street&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Westfield&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NJ&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;postalCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;07090&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;US&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;showStreet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// set to false for a service-area business that hides its address&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;geo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;40.65899&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lng&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;74.34737&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;days&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Monday&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tuesday&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Wednesday&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thursday&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Friday&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;opens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;08:00&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;closes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;18:00&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;days&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Saturday&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;opens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;09:00&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;closes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;13:00&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;serviceAreas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Westfield&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cranford&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Scotch Plains&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mountainside&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;profiles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://www.facebook.com/westfieldplumbing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://www.yelp.com/biz/westfield-plumbing-co&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then every template reads from it. In JSX, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;business&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../config/business.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;CallButton&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`tel:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;business&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;e164&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Call &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;business&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Storing the phone number in both a display format and the international E.164 format means the visible number and the &lt;code&gt;tel:&lt;/code&gt; link can never drift apart. When the client changes their hours or moves, you update one file, and the header, footer, contact page and structured data all change together.&lt;/p&gt;

&lt;h2&gt;
  
  
  LocalBusiness Structured Data That's Actually Right
&lt;/h2&gt;

&lt;p&gt;Structured data tells search engines explicitly what the business is, where it operates and when it's open. Generate it from the same config, so it always matches the visible page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/local-business-jsonld.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;business&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../config/business.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;localBusinessJsonLd&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;business&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@context&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://schema.org&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;business&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;business&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/#business`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;business&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;business&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;telephone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;business&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;e164&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PostalAddress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;...(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;showStreet&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;streetAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;street&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="na"&gt;addressLocality&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;addressRegion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;postalCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;postalCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;addressCountry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;...(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;showStreet&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;geo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GeoCoordinates&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;business&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;business&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lng&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="na"&gt;openingHoursSpecification&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;business&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OpeningHoursSpecification&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;dayOfWeek&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;days&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;opens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;opens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;closes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;closes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})),&lt;/span&gt;
    &lt;span class="na"&gt;areaServed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;business&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceAreas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;City&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;})),&lt;/span&gt;
    &lt;span class="na"&gt;sameAs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;business&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;profiles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Render it in a &lt;code&gt;&amp;lt;script type="application/ld+json"&amp;gt;&lt;/code&gt; tag on the homepage and contact page, escaping &lt;code&gt;&amp;lt;&lt;/code&gt; characters when you inject it, just as you would for any JSON-LD.&lt;/p&gt;

&lt;p&gt;A few rules from &lt;a href="https://developers.google.com/search/docs/appearance/structured-data/local-business" rel="noopener noreferrer"&gt;Google's LocalBusiness structured data documentation&lt;/a&gt; are worth knowing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;name&lt;/code&gt; and &lt;code&gt;address&lt;/code&gt; are required.&lt;/strong&gt; Everything else, including &lt;code&gt;telephone&lt;/code&gt;, &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;geo&lt;/code&gt; and &lt;code&gt;openingHoursSpecification&lt;/code&gt;, is recommended.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use the most specific type available,&lt;/strong&gt; like &lt;code&gt;Plumber&lt;/code&gt;, &lt;code&gt;Electrician&lt;/code&gt; or &lt;code&gt;HairSalon&lt;/code&gt;, rather than the generic &lt;code&gt;LocalBusiness&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mark up each location separately&lt;/strong&gt; for multi-location businesses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geo coordinates&lt;/strong&gt; should use at least five decimal places.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a service-area business that doesn't show its street address publicly, include only the address details you actually display, such as the city, region and postal code, and leave out the geo coordinates, as the generator above does when &lt;code&gt;showStreet&lt;/code&gt; is false. Then check the result in Google's Rich Results Test.&lt;/p&gt;

&lt;p&gt;And set the right expectations with clients. Google says this markup can help with things like knowledge panels, but it doesn't claim LocalBusiness markup improves map pack rankings. It's about accuracy and clarity, not a ranking switch.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Conversion Details Local Customers Need
&lt;/h2&gt;

&lt;p&gt;Local search visitors usually want to act quickly, often on a phone, sometimes in an emergency. A few details make a big difference:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A click-to-call button,&lt;/strong&gt; visible near the top of every page on mobile.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hours and service areas&lt;/strong&gt; that are easy to find, not buried on the contact page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A short contact form&lt;/strong&gt; that works well on a phone. Name, phone, a short message and you're done.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trust signals:&lt;/strong&gt; licence numbers, insurance, years in business and photos of real jobs and real staff.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Maps deserve special attention. A Google Maps embed loads a lot of JavaScript, and putting one on every page, or at the top of the contact page, is a common cause of slow mobile scores. A simple facade loads the map only when someone asks for it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"map-facade"&lt;/span&gt; &lt;span class="na"&gt;data-src=&lt;/span&gt;&lt;span class="s"&gt;"https://www.google.com/maps/embed?pb=YOUR_EMBED_CODE"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Show map and directions&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nc"&gt;.map-facade&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;aspect-ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="py"&gt;place-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#eef2f5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.map-facade&lt;/span&gt; &lt;span class="nt"&gt;iframe&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.map-facade&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;iframe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;iframe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;iframe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;iframe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Map showing our location&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;iframe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lazy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceChildren&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iframe&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;aspect-ratio&lt;/code&gt; reserves the space up front, so the page doesn't shift when the map loads, which protects your Cumulative Layout Shift score. If the map sits well below the fold, a plain iframe with &lt;code&gt;loading="lazy"&lt;/code&gt; can be enough on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reviews: Show Them Without Breaking Rules or Performance
&lt;/h2&gt;

&lt;p&gt;Reviews feed directly into prominence, so the site should make leaving one easy. Link to the business's Google review URL from confirmation emails, invoices and receipts, and add a simple "Leave us a review" link on the site.&lt;/p&gt;

&lt;p&gt;Two rules matter here. First, don't build a "review gating" flow that asks customers how they feel and only sends the happy ones to Google. Google's policies prohibit selectively asking for positive reviews. If the client wants a fuller picture of what's allowed, Clutchpilot has a guide on &lt;a href="https://clutchpilot.com/blog/how-to-get-more-reviews" rel="noopener noreferrer"&gt;how to get more reviews without breaking the rules&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Second, don't mark up the business's own reviews as star ratings in its structured data. Google's review snippet guidelines say that when a business controls the reviews about itself, its pages using LocalBusiness or Organization structured data are ineligible for star review rich results, and that includes reviews shown through an embedded third-party widget. Show reviews to visitors, by all means, but leave &lt;code&gt;aggregateRating&lt;/code&gt; out of the business's own JSON-LD.&lt;/p&gt;

&lt;p&gt;If you embed a reviews widget, lazy-load it and reserve its space, for the same performance reasons as the map.&lt;/p&gt;

&lt;h2&gt;
  
  
  Citations and Local Links
&lt;/h2&gt;

&lt;p&gt;Citations are listings of the business on other sites, like Yelp, Facebook, Bing Places, industry directories and the local chamber of commerce. The key is consistency. Every listing should use exactly the same name, address and phone number as the website and profile, which is another reason to keep NAP in one place.&lt;/p&gt;

&lt;p&gt;Links from genuinely local sources help prominence too: suppliers and manufacturers, trade associations, local sponsorships, community organizations and local news coverage. What doesn't help is buying links or paying for bulk directory submissions. They're low quality at best and a spam risk at worst.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measuring Local SEO
&lt;/h2&gt;

&lt;p&gt;You can't improve what you can't see, so set up measurement from day one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google Business Profile performance&lt;/strong&gt; shows calls, direction requests and website clicks from the profile.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Search Console&lt;/strong&gt; shows which searches bring people to the site. Watch queries that include town names or "near me."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics,&lt;/strong&gt; with the UTM-tagged profile link, separates profile traffic from other search traffic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Call tracking&lt;/strong&gt; can show which channels drive calls, but be careful with NAP. Use dynamic number insertion on the website if you need it, and keep the main business number on the Business Profile and in citations, so consistency isn't broken.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A baseline technical check.&lt;/strong&gt; Run a &lt;a href="https://seositechecker.pro/website-seo-score-checker" rel="noopener noreferrer"&gt;free website audit&lt;/a&gt; at launch and every few months, to catch slow pages, missing titles and broken links before they cost the client visibility.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Keyword-stuffed business names on the profile.&lt;/li&gt;
&lt;li&gt;Fake addresses or virtual offices used to appear in a town where the business has no real presence.&lt;/li&gt;
&lt;li&gt;Dozens of near-identical city pages.&lt;/li&gt;
&lt;li&gt;Phone numbers and hours hardcoded in several templates.&lt;/li&gt;
&lt;li&gt;Heavy map embeds loading on every page.&lt;/li&gt;
&lt;li&gt;Review gating flows.&lt;/li&gt;
&lt;li&gt;Self-serving review markup in the business's own structured data.&lt;/li&gt;
&lt;li&gt;No UTM tag on the profile link, making results impossible to measure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to Bring in Local SEO Help
&lt;/h2&gt;

&lt;p&gt;Good local SEO for small business owners doesn't usually need an agency at first. The basics in this guide will put most small service businesses ahead of their local competitors. It's worth bringing in a specialist when the market is very competitive (think personal injury lawyers or HVAC in a big metro area), when the business has several locations, or when it's still invisible after the fundamentals are in place.&lt;/p&gt;

&lt;p&gt;Look for someone who starts with an audit, explains what they'll do and why, builds genuine local links rather than buying bulk listings, and never promises a guaranteed spot in the map pack, because Google says there's no way to buy one. A &lt;a href="https://nexibloom.com/services/search-engine-optimization-seo" rel="noopener noreferrer"&gt;local SEO audit and consultation&lt;/a&gt; is a sensible first step before committing to anything ongoing.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is local SEO for a small business?
&lt;/h3&gt;

&lt;p&gt;Local SEO for a small business is the work of helping it appear when people nearby search for its products or services. It covers the Google Business Profile, a website with clear service and location information, consistent business details across the web, reviews and local links. It's especially important for service businesses.&lt;/p&gt;

&lt;h3&gt;
  
  
  How long does local SEO take to work?
&lt;/h3&gt;

&lt;p&gt;Fixing a Business Profile and basic website issues can show results within weeks, but building strong local rankings usually takes a few months of steady work. Reviews, links and content build up over time, and results depend heavily on how competitive the local market is.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need a website for local SEO?
&lt;/h3&gt;

&lt;p&gt;You can appear in the map results with just a Google Business Profile, but a website helps a lot. It supports relevance and prominence, gives Google more detail about your services, ranks in the local organic results and gives customers a place to learn more and contact you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can a service-area business rank without a physical address?
&lt;/h3&gt;

&lt;p&gt;Yes. Service-area businesses can hide their address on their Google Business Profile and list up to 20 service areas, within about two hours' drive of the business. Distance still matters, so rankings are strongest near the business's actual base.&lt;/p&gt;

&lt;h3&gt;
  
  
  How many location or service-area pages should I create?
&lt;/h3&gt;

&lt;p&gt;Only as many as you can fill with genuinely local, useful content, such as jobs completed in the area, local details and area-specific questions. Google's spam policies warn against near-identical city pages that funnel users to the same place, so a few strong pages beat many thin ones.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does LocalBusiness schema improve local rankings?
&lt;/h3&gt;

&lt;p&gt;Not directly, as far as Google has said. LocalBusiness structured data helps search engines understand the business's details accurately, and Google says it can help with features like knowledge panels. Map pack rankings depend mainly on relevance, distance and prominence, driven largely by the Business Profile.&lt;/p&gt;

&lt;h3&gt;
  
  
  How much does local SEO cost?
&lt;/h3&gt;

&lt;p&gt;Many of the basics are free, including setting up a Google Business Profile, fixing website details and asking for reviews. Agencies typically charge a monthly fee that varies widely with competition and scope. In very competitive markets, ongoing professional help can be worth the investment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Local SEO is half Business Profile and half website. On the website side, your job as a developer is clear: build genuinely useful service pages, avoid doorway city pages, keep the business details in one source of truth, generate accurate structured data, make it effortless to call or get directions, and make every click measurable. Do that, and you'll stop getting emails asking why the client isn't on the map, or at least you'll be able to show them exactly why, and what's improving.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>seo</category>
      <category>beginners</category>
      <category>javascript</category>
    </item>
    <item>
      <title>JSON-LD Schema Basics for Developers</title>
      <dc:creator>Jay Barker</dc:creator>
      <pubDate>Fri, 23 Oct 2026 16:10:00 +0000</pubDate>
      <link>https://dev.to/jaybarker/json-ld-schema-basics-for-developers-1p4</link>
      <guid>https://dev.to/jaybarker/json-ld-schema-basics-for-developers-1p4</guid>
      <description>&lt;p&gt;The ticket says "Add schema to the product pages." Simple enough. You search for "JSON-LD schema," and half the results are about JSON Schema, which turns out to be something else entirely. The other half are SEO blogs showing FAQ markup that Google stopped rewarding years ago.&lt;/p&gt;

&lt;p&gt;Structured data is one of the most useful parts of technical SEO and one of the most misunderstood. Done well, it tells search engines exactly what a page is about: this is a product, here's its price, this is the company that sells it. Done badly, it's a block of stale, hand-written JSON that quietly contradicts the page it sits on.&lt;/p&gt;

&lt;p&gt;In this guide, I'll untangle the terminology, walk through a JSON-LD block line by line, cover the schema types still worth adding in 2026 (and the ones Google has dropped), show how to link entities with &lt;code&gt;@graph&lt;/code&gt;, generate the markup safely from your data, and test it automatically.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; I work with the team behind SEO Site Checker, whose tools I mention below. Everything else here is tool-agnostic.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Short Version
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JSON-LD is a format. Schema.org is the vocabulary you use inside it.&lt;/strong&gt; Together, they're what people mean by "JSON-LD schema."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google recommends JSON-LD,&lt;/strong&gt; and it can go in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; or the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only mark up content that's visible on the page.&lt;/strong&gt; No hidden or invented data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured data helps Google understand a page and can enable rich results,&lt;/strong&gt; but it doesn't guarantee them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generate it from your data, inject it safely and validate it in CI.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  First, Clear Up the Naming Confusion
&lt;/h2&gt;

&lt;p&gt;Three different things get mixed up here, so let's separate them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JSON-LD&lt;/strong&gt; stands for JSON for Linked Data. It's a W3C standard for expressing linked data in ordinary JSON, using special keywords like &lt;code&gt;@context&lt;/code&gt;, &lt;code&gt;@type&lt;/code&gt; and &lt;code&gt;@id&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schema.org&lt;/strong&gt; is a shared vocabulary of types (Product, Organization, Article, Event and hundreds more) and their properties. It's maintained collaboratively and backed by the major search engines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSON Schema&lt;/strong&gt; is an unrelated specification for describing and validating the shape of JSON documents, usually API requests and responses. It has nothing to do with SEO.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then there's &lt;strong&gt;structured data markup&lt;/strong&gt;, the umbrella term for adding machine-readable data to a page. It can be written as JSON-LD, Microdata or RDFa. Microdata and RDFa weave attributes into your HTML, while JSON-LD lives in its own script tag, which is why it's much easier to generate and maintain.&lt;/p&gt;

&lt;p&gt;So when an SEO ticket says "JSON-LD schema," it means Schema.org vocabulary written in JSON-LD. You can close the JSON Schema tabs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anatomy of a JSON-LD Block
&lt;/h2&gt;

&lt;p&gt;Here's a minimal, valid Organization block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"application/ld+json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@context&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://schema.org&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Organization&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Acme Tools&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com/images/logo.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sameAs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://www.linkedin.com/company/acme-tools&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://www.instagram.com/acmetools&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contactPoint&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ContactPoint&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;telephone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;+1-555-555-0123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contactType&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;customer service&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Line by line:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;&amp;lt;script type="application/ld+json"&amp;gt;&lt;/code&gt;&lt;/strong&gt; tells the browser this is data, not code to execute. Nothing renders on the page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;@context&lt;/code&gt;&lt;/strong&gt; says which vocabulary the keys come from, which here is Schema.org.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;@type&lt;/code&gt;&lt;/strong&gt; is the kind of thing you're describing. Types use PascalCase and are case-sensitive, so &lt;code&gt;Organization&lt;/code&gt; works and &lt;code&gt;organization&lt;/code&gt; doesn't.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Properties&lt;/strong&gt; like &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;url&lt;/code&gt; and &lt;code&gt;logo&lt;/code&gt; describe it. Properties use camelCase.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nested objects&lt;/strong&gt; have their own &lt;code&gt;@type&lt;/code&gt;. Here, &lt;code&gt;contactPoint&lt;/code&gt; is a ContactPoint, not just a loose object.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Arrays&lt;/strong&gt; hold multiple values. &lt;code&gt;sameAs&lt;/code&gt; lists your official profiles elsewhere, which helps search engines connect them to the same entity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use full absolute URLs everywhere, and make sure every value is valid JSON: double quotes only, and no trailing commas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to Put It and How Google Reads It
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data" rel="noopener noreferrer"&gt;Google's introduction to structured data&lt;/a&gt; recommends JSON-LD and says it can go in either the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; or the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;. A page can have several JSON-LD blocks, so a product page might have one for the product and another for breadcrumbs.&lt;/p&gt;

&lt;p&gt;Google can also read JSON-LD injected with JavaScript after the page loads. That works, but server-rendering it is more reliable, because it's in the HTML from the first byte and other crawlers that don't run JavaScript can see it too.&lt;/p&gt;

&lt;p&gt;The rule that matters most is this one: &lt;strong&gt;structured data must describe content that's visible on that page.&lt;/strong&gt; If the JSON-LD says a product costs $49 and is in stock, the page should say the same. Marking up hidden content, or data that isn't on the page at all, goes against Google's guidelines and can lead to the markup being ignored.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Schema Types Worth Adding in 2026
&lt;/h2&gt;

&lt;p&gt;You don't need dozens of types. For most sites, these cover the important ground. The full vocabulary lives on &lt;a href="https://schema.org/" rel="noopener noreferrer"&gt;Schema.org&lt;/a&gt; if you need something more specific.&lt;/p&gt;

&lt;h3&gt;
  
  
  Organization or LocalBusiness
&lt;/h3&gt;

&lt;p&gt;Every site should describe who's behind it. Use Organization for most businesses, or LocalBusiness (or a more specific subtype, like Dentist or Restaurant) if customers visit a physical location:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schema.org"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LocalBusiness"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Happy Paws Grooming"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://happypaws.example"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"telephone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"+1-555-555-0188"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PostalAddress"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"streetAddress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"12 Main Street"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"addressLocality"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Westfield"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"addressRegion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NJ"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"postalCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"07090"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"addressCountry"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"US"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"openingHoursSpecification"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OpeningHoursSpecification"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dayOfWeek"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Monday"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tuesday"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Wednesday"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Thursday"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Friday"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"opens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"09:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"closes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"17:00"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  WebSite
&lt;/h3&gt;

&lt;p&gt;A small block on your homepage that states your site's name, which helps Google show the right site name in results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schema.org"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WebSite"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Acme Tools"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  BreadcrumbList
&lt;/h3&gt;

&lt;p&gt;This should mirror the breadcrumbs users actually see on the page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schema.org"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BreadcrumbList"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"itemListElement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ListItem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Power Tools"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"item"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/power-tools"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ListItem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Drills"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"item"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/power-tools/drills"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Article or BlogPosting
&lt;/h3&gt;

&lt;p&gt;For editorial content, include the headline, author, dates and a representative image. Keep &lt;code&gt;dateModified&lt;/code&gt; honest. Bumping it without real changes doesn't fool anyone.&lt;/p&gt;

&lt;h3&gt;
  
  
  Product with Offer and AggregateRating
&lt;/h3&gt;

&lt;p&gt;For ecommerce, this is the big one. Price, currency, availability and, if you have them, reviews. Only include ratings from genuine reviews that are visible on the page. Self-written or invented ratings break Google's guidelines.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schema.org"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Cordless Drill 18V"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/images/drill-1600.jpg"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Lightweight 18V cordless drill with two batteries."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ACME-DRL-18"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"brand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Brand"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Acme Tools"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"offers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Offer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/products/cordless-drill-18v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"priceCurrency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"129.00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"availability"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schema.org/InStock"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"aggregateRating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AggregateRating"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ratingValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4.6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"reviewCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"87"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Others, when they genuinely fit
&lt;/h3&gt;

&lt;p&gt;Event, Recipe, JobPosting and VideoObject are all well supported when your content actually is one of those things. Don't force a type onto a page that isn't that type.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Changed: Rich Results Google No Longer Shows
&lt;/h2&gt;

&lt;p&gt;This is the part most JSON-LD guides haven't caught up with. Google has been steadily trimming which structured data features produce special search results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FAQ rich results&lt;/strong&gt; have been limited to well-known, authoritative government and health websites since 2023. For almost everyone else, FAQ markup no longer produces the expandable questions in search.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HowTo rich results&lt;/strong&gt; were dropped.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In June 2025,&lt;/strong&gt; as part of simplifying the search results page, Google phased out seven more features: Book Actions, Course Info, Claim Review, Estimated Salary, Learning Video, Special Announcement and Vehicle Listing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In November 2025,&lt;/strong&gt; Google said Practice Problems markup would be deprecated, and that Dataset markup would only be used in Dataset Search rather than in main search results.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What should you do with markup for deprecated features? Nothing dramatic. Leaving it in place won't trigger errors or hurt your site, and some markup is still useful to other consumers of your data. Just don't add new markup expecting a rich result that no longer exists, and don't promise a client those FAQ dropdowns.&lt;/p&gt;

&lt;p&gt;One more expectation to set: Google describes structured data as a way to help it understand your content and enable richer displays. It doesn't describe it as a ranking boost. Good structured data makes a good page easier to understand. It won't rescue a weak one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Linking Entities With &lt;a class="mentioned-user" href="https://dev.to/graph"&gt;@graph&lt;/a&gt; and &lt;a class="mentioned-user" href="https://dev.to/id"&gt;@id&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A single page often describes several connected things: the organization, the website, the web page and the article with its author. Instead of repeating the organization in every block, you can put everything in one &lt;code&gt;@graph&lt;/code&gt; and connect the pieces with &lt;code&gt;@id&lt;/code&gt; references:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schema.org"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@graph"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Organization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/#organization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Acme Tools"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"logo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/images/logo.png"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WebSite"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/#website"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Acme Tools"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"publisher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"@id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/#organization"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Person"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/team/jay#person"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Jay Barker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/team/jay"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BlogPosting"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/blog/choosing-a-drill#article"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"headline"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"How to Choose a Cordless Drill"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"datePublished"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-12-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dateModified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-12-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"@id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/team/jay#person"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"publisher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"@id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/#organization"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"isPartOf"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"@id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/#website"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"mainEntityOfPage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/blog/choosing-a-drill"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An &lt;code&gt;@id&lt;/code&gt; is just a unique identifier, conventionally a URL with a hash fragment. It doesn't need to resolve to a page, but it must be consistent. Use the same &lt;code&gt;@id&lt;/code&gt; for your organization on every page, and search engines can understand that it's one entity rather than many.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate It From Data, Don't Hand-Write It
&lt;/h2&gt;

&lt;p&gt;Hand-written JSON-LD has a fatal flaw: it drifts. Someone changes a price in the CMS, and the structured data still says the old one. The fix is to generate JSON-LD from the same data that renders the visible page.&lt;/p&gt;

&lt;p&gt;Here's a small, reusable component for Next.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// components/JsonLd.tsx&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;JsonLdProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;JsonLd&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;JsonLdProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Escape "&amp;lt;" so a value like "&amp;lt;/script&amp;gt;" can't break out of the tag&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&amp;lt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;u003c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"application/ld+json"&lt;/span&gt;
      &lt;span class="na"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And using it on a product page in the App Router:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/products/[slug]/page.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;JsonLd&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/JsonLd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ProductPage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;productJsonLd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@context&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://schema.org&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Product&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;images&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;brand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Brand&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;brand&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;offers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Offer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`https://example.com/products/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;priceCurrency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;availability&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inStock&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://schema.org/InStock&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://schema.org/OutOfStock&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;JsonLd&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;productJsonLd&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* the visible product page, rendered from the same `product` data */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Don't skip the escaping.&lt;/strong&gt; &lt;code&gt;JSON.stringify&lt;/code&gt; produces valid JSON, but it doesn't make that JSON safe to drop inside a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag. If any value comes from users or editors, such as a product name or a review, a string containing &lt;code&gt;&amp;lt;/script&amp;gt;&lt;/code&gt; can close the tag early and inject arbitrary HTML. That's a cross-site scripting (XSS) hole. Replacing every &lt;code&gt;&amp;lt;&lt;/code&gt; with &lt;code&gt;&amp;lt;&lt;/code&gt; keeps the JSON identical once it's parsed, while making it impossible to break out of the script tag.&lt;/p&gt;

&lt;p&gt;The same pattern works anywhere. In Astro, Nuxt, Rails or a PHP template, build a plain object from your data, serialize it, escape &lt;code&gt;&amp;lt;&lt;/code&gt; and render it in a script tag from one shared component. If you're on a CMS, plugins can output schema for you. Just check what they produce, because two plugins each emitting their own Organization block is a surprisingly common mess.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing and Validation
&lt;/h2&gt;

&lt;p&gt;There are several layers of checking, and each catches different problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google's &lt;a href="https://search.google.com/test/rich-results" rel="noopener noreferrer"&gt;Rich Results Test&lt;/a&gt;&lt;/strong&gt; shows whether a page is eligible for Google's rich results and flags errors in the properties Google cares about.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Schema Markup Validator&lt;/strong&gt; at validator.schema.org checks general Schema.org validity, including types Google doesn't use for rich results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Search Console&lt;/strong&gt; shows rich result reports across your site, and the URL Inspection tool confirms what Google actually found on a specific page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For quick manual checks, it helps to format and inspect the raw JSON before anything else. SEO Site Checker has &lt;a href="https://seositechecker.pro/tools" rel="noopener noreferrer"&gt;free developer tools, including a JSON viewer and formatter&lt;/a&gt;, that make a minified block readable in seconds. For a broader view, a &lt;a href="https://seositechecker.pro/website-seo-score-checker" rel="noopener noreferrer"&gt;site-wide audit that checks structured data&lt;/a&gt; flags pages where it's missing or broken.&lt;/p&gt;

&lt;p&gt;But the real win is automation. Here's a small Node script (Node 18 or newer) that fetches pages, extracts every JSON-LD block, confirms it parses, and checks that each node has a &lt;code&gt;@type&lt;/code&gt; and the properties you consider required:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// scripts/check-jsonld.mjs&lt;/span&gt;
&lt;span class="c1"&gt;// Usage: node scripts/check-jsonld.mjs https://staging.example.com/ https://staging.example.com/products/sample&lt;/span&gt;

&lt;span class="c1"&gt;// Adjust to the properties you require for the features you care about&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;REQUIRED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;Organization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;LocalBusiness&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;offers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;BlogPosting&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;headline&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;datePublished&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;headline&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;datePublished&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;BreadcrumbList&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itemListElement&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;failed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`FAIL &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nx"&gt;failed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SCRIPT_RE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&amp;lt;script&lt;/span&gt;&lt;span class="se"&gt;[^&lt;/span&gt;&lt;span class="sr"&gt;&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*type=&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;application&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;ld&lt;/span&gt;&lt;span class="se"&gt;\+&lt;/span&gt;&lt;span class="sr"&gt;json&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;][^&lt;/span&gt;&lt;span class="sr"&gt;&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;([\s\S]&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;?)&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;script&amp;gt;/gi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blocks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matchAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SCRIPT_RE&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no JSON-LD found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`invalid JSON: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@graph&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;types&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[].&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a node has no @type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prop&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;REQUIRED&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is missing "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;failed&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's deliberately simple. It won't replace Google's tools, but it will fail your build the moment a template change breaks the JSON or drops a property you rely on, which is exactly when you want to know.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does Structured Data Help With AI Search?
&lt;/h2&gt;

&lt;p&gt;It's the question I get most often now, so here's the honest answer. Google says there's no special schema you need to add to appear in AI Overviews or AI Mode. Its AI features rely on the same indexing and quality systems as regular search, and the same structured data guidelines apply.&lt;/p&gt;

&lt;p&gt;That doesn't make structured data useless for AI. Clear, accurate structured data markup removes ambiguity. It states plainly that this page is about a product called "Cordless Drill 18V," made by this brand, costing this much and in stock. Any system reading your page, whether it's a search engine, an AI assistant, a shopping feed or a voice assistant, benefits from facts that are explicit rather than inferred. Consistent &lt;code&gt;@id&lt;/code&gt;s and &lt;code&gt;sameAs&lt;/code&gt; links also help connect your business to the same entity across the web.&lt;/p&gt;

&lt;p&gt;What it won't do is get your content cited by an AI tool on its own. Be wary of anyone selling a special "AI schema" that promises AI visibility. The fundamentals still decide that: useful content, a trusted reputation and pages that can be crawled.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Rollout Plan
&lt;/h2&gt;

&lt;p&gt;If you're adding structured data to an existing site, don't try to mark up everything at once. Roll it out in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Sitewide entities first.&lt;/strong&gt; Add Organization (or LocalBusiness) and WebSite once, ideally in a shared layout, with stable &lt;code&gt;@id&lt;/code&gt;s.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your money templates next.&lt;/strong&gt; Product pages for ecommerce, service or location pages for local businesses, articles for publishers. One template change covers hundreds of pages.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Breadcrumbs everywhere they're visible.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add the CI check&lt;/strong&gt; from the testing section before you move on, so nothing regresses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch Search Console&lt;/strong&gt; for a few weeks. Fix errors and warnings in the rich result reports, and confirm with URL Inspection that Google sees what you expect.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then stop, and only add more types when a page genuinely is one of them. More schema isn't better schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Markup that doesn't match the page,&lt;/strong&gt; like a price, rating or availability that differs from what users see.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fake or self-written reviews&lt;/strong&gt; in AggregateRating.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relative URLs&lt;/strong&gt; in &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;image&lt;/code&gt; or &lt;code&gt;item&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The wrong type,&lt;/strong&gt; such as Article on a product page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Several conflicting Organization blocks,&lt;/strong&gt; usually from a theme and a plugin both adding their own.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invalid JSON,&lt;/strong&gt; most often from trailing commas or single quotes in hand-written blocks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expecting FAQ or HowTo rich results&lt;/strong&gt; in 2026.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unescaped user content&lt;/strong&gt; inside the script tag.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is JSON-LD schema?
&lt;/h3&gt;

&lt;p&gt;JSON-LD schema usually means Schema.org structured data written in the JSON-LD format. It's a script block, typed &lt;code&gt;application/ld+json&lt;/code&gt;, that describes what a page is about, such as a product, business or article, in a machine-readable way that search engines can understand.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's the difference between JSON-LD and JSON Schema?
&lt;/h3&gt;

&lt;p&gt;They're unrelated. JSON-LD is a format for linked data, used with the Schema.org vocabulary to describe web content for search engines. JSON Schema is a specification for validating the structure of JSON documents, typically API payloads. Only JSON-LD is relevant to SEO.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is JSON-LD better than Microdata?
&lt;/h3&gt;

&lt;p&gt;For most sites, yes. Google recommends JSON-LD because it sits in its own script block, separate from your HTML, which makes it easier to generate, maintain and debug. Microdata and RDFa are still valid, but they tie your structured data to your markup, which gets messy fast.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should JSON-LD go in the head or the body?
&lt;/h3&gt;

&lt;p&gt;Either works. Google reads JSON-LD in both the head and the body, and a page can have more than one block. Put it wherever your framework makes it easiest to generate from the page's data, ideally server-rendered so it's in the initial HTML.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does schema markup help SEO rankings?
&lt;/h3&gt;

&lt;p&gt;Not directly. Google describes structured data as a way to help it understand your content and to enable rich results, not as a ranking boost. It can still help indirectly, for example by making your results more informative, but it won't make a weak page rank.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I add JSON-LD with JavaScript or Google Tag Manager?
&lt;/h3&gt;

&lt;p&gt;Yes. Google can read JSON-LD that's injected with JavaScript, including through Google Tag Manager. Server-rendering it is more reliable, though, because it's present in the initial HTML and visible to crawlers that don't run JavaScript. Either way, keep it in sync with the visible content.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does valid JSON-LD guarantee rich results?
&lt;/h3&gt;

&lt;p&gt;No. Valid markup makes a page eligible, but Google decides whether to show rich results based on many factors, and it has retired several rich result types in recent years. Use the Rich Results Test to check eligibility, and treat any rich result as a bonus.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Treat structured data like any other output of your code. Generate it from real data, inject it safely, keep it truthful to what's on the page and test it in CI. JSON-LD won't rank a page on its own, but it makes your content far easier for search engines, and the growing number of other machines reading the web, to understand correctly.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>seo</category>
      <category>javascript</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Compress Images Before You Upload: A Faster Website Workflow</title>
      <dc:creator>Jay Barker</dc:creator>
      <pubDate>Thu, 22 Oct 2026 21:00:00 +0000</pubDate>
      <link>https://dev.to/jaybarker/compress-images-before-you-upload-a-faster-website-workflow-4953</link>
      <guid>https://dev.to/jaybarker/compress-images-before-you-upload-a-faster-website-workflow-4953</guid>
      <description>&lt;p&gt;You run Lighthouse on a page you just shipped, and there it is again, right at the top of the report: "Properly size images." Underneath, a list of offenders, led by a 4.2 MB hero photo that someone exported straight from a camera and dropped into the CMS.&lt;/p&gt;

&lt;p&gt;Images are usually the heaviest thing on a web page, and they're often the Largest Contentful Paint element too, which means they directly affect how fast your page feels and how it scores in Core Web Vitals. The fix isn't complicated, but it does need a consistent workflow, because "remember to compress it" is not a process.&lt;/p&gt;

&lt;p&gt;So if you've been searching for how to compress images for a website properly, this is the workflow I use. It's six steps, a short script that does most of it in one command, and the HTML to serve the results the right way.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; I work with the team behind SEO Site Checker, whose image compressor I mention below. The rest of the workflow uses open-source tools.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Workflow in 60 Seconds
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Resize&lt;/strong&gt; to the largest size you actually display.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choose the right format&lt;/strong&gt; for the job.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compress&lt;/strong&gt; with sensible quality settings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strip metadata&lt;/strong&gt; you don't need.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automate it,&lt;/strong&gt; so it happens every time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serve it properly&lt;/strong&gt; with &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;, &lt;code&gt;srcset&lt;/code&gt; and the right loading hints.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why Compress Before Upload, Not After
&lt;/h2&gt;

&lt;p&gt;Most CMS platforms and plugins can optimize images after you upload them. That's better than nothing, but it has real downsides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The original still lands on your server.&lt;/strong&gt; It gets stored, backed up and sometimes served, depending on how the theme handles image sizes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Big files bloat your Git repo forever.&lt;/strong&gt; If your images live in the repo, a 6 MB PNG committed once stays in your history permanently, even after you replace it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You give up control.&lt;/strong&gt; Automatic optimizers apply one-size-fits-all settings. Some are too aggressive and leave visible artifacts. Others barely touch the file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Results are inconsistent.&lt;/strong&gt; Different people, different tools, different outcomes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compressing before upload means every image arrives at the right size, in the right format and at the right quality, whether it's going into a CMS, a static site or a Git repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Resize to the Size You Actually Display
&lt;/h2&gt;

&lt;p&gt;Resizing is the biggest single win, and it's the step people skip most often. A modern phone photo is often 4,000 pixels wide. If it displays in an 800-pixel column, roughly 96% of those pixels are thrown away by the browser after being downloaded.&lt;/p&gt;

&lt;p&gt;A few rules of thumb:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Export at the width you display,&lt;/strong&gt; or up to 2x that width for important images on high-density screens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cap hero images at around 1,600 to 2,000 pixels wide.&lt;/strong&gt; Larger rarely looks better, but it's always heavier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate a few widths&lt;/strong&gt; (for example 480, 960 and 1600) so the browser can pick the right one with &lt;code&gt;srcset&lt;/code&gt;. More on that in Step 6.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The reason 2x isn't a free lunch is that file size grows with pixel count, not width. As &lt;a href="https://web.dev/articles/choose-the-right-image-format" rel="noopener noreferrer"&gt;web.dev's guide to choosing the right image format&lt;/a&gt; points out, doubling an image's resolution quadruples its pixels. So use 2x where it matters, not everywhere.&lt;/p&gt;

&lt;p&gt;With sharp, resizing is one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;sharp&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sharp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sharp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;photo.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                 &lt;span class="c1"&gt;// apply EXIF orientation before metadata is removed&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;withoutEnlargement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;photo-1600.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Pick the Right Format
&lt;/h2&gt;

&lt;p&gt;Format choice matters almost as much as compression settings. Here's the short version:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;JPEG&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Photos&lt;/td&gt;
&lt;td&gt;Universal support. The safe fallback.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PNG&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Screenshots, graphics with sharp edges, transparency&lt;/td&gt;
&lt;td&gt;Lossless, so files are large. Don't use it for photos.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WebP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Almost everything raster&lt;/td&gt;
&lt;td&gt;Smaller than JPEG and PNG, supports transparency.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AVIF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Photos and complex images&lt;/td&gt;
&lt;td&gt;Often smaller than WebP. Slower to encode.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SVG&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Logos, icons, simple illustrations&lt;/td&gt;
&lt;td&gt;Vector, so sharp at any size and usually tiny.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GIF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Nothing, really&lt;/td&gt;
&lt;td&gt;Use a short video file for animation instead.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;WebP is the easy default today. &lt;a href="https://developers.google.com/speed/webp" rel="noopener noreferrer"&gt;Google's WebP documentation&lt;/a&gt; reports that lossy WebP images are 25 to 34% smaller than comparable JPEGs at equivalent quality, and lossless WebP images are 26% smaller than PNGs. It's supported in Chrome, Safari, Firefox, Edge and Opera.&lt;/p&gt;

&lt;p&gt;AVIF can go smaller still, and it's supported by current versions of all the major browsers. The trade-offs are slower encoding and, at very low quality settings, some color shifts. Serving AVIF with a WebP or JPEG fallback (Step 6) gives you the best of both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Compress With Sensible Settings
&lt;/h2&gt;

&lt;p&gt;First, a quick reality check on the phrase you'll see everywhere: "compress without losing quality." For PNG and lossless WebP, that's literally true. Lossless compression just stores the same pixels more efficiently.&lt;/p&gt;

&lt;p&gt;For JPEG, lossy WebP and AVIF, compression permanently discards some image data. There is &lt;em&gt;some&lt;/em&gt; quality loss. The goal is to make that loss invisible to the human eye while cutting the file size dramatically. That's very achievable with the right settings.&lt;/p&gt;

&lt;p&gt;Good starting points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JPEG:&lt;/strong&gt; quality 75 to 85. Use MozJPEG if your tool supports it, as it squeezes out extra savings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebP:&lt;/strong&gt; quality 75 to 85.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AVIF:&lt;/strong&gt; around 50 to 65. AVIF's quality scale isn't the same as JPEG's, so a lower number doesn't mean worse-looking.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Always compare the result against the original at 100% zoom, especially on faces, text and smooth gradients, which show artifacts first.&lt;/p&gt;

&lt;p&gt;For tools, pick whatever fits the situation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One-off images:&lt;/strong&gt; a &lt;a href="https://seositechecker.pro/image-compressor" rel="noopener noreferrer"&gt;free online image compressor&lt;/a&gt; handles PNG, JPEG and WebP files in a few seconds, with no settings to fiddle with. It's handy when someone sends you a single image and you just need it smaller.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visual comparison:&lt;/strong&gt; Squoosh, Google's browser-based app, shows the original and compressed versions side by side with a slider, which is great for finding the right quality level.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scripting:&lt;/strong&gt; command-line tools work well in build scripts:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# WebP at quality 80&lt;/span&gt;
cwebp &lt;span class="nt"&gt;-q&lt;/span&gt; 80 input.jpg &lt;span class="nt"&gt;-o&lt;/span&gt; output.webp

&lt;span class="c"&gt;# AVIF at quality 60&lt;/span&gt;
avifenc &lt;span class="nt"&gt;-q&lt;/span&gt; 60 input.jpg output.avif

&lt;span class="c"&gt;# Resize, strip metadata and recompress a JPEG with ImageMagick&lt;/span&gt;
magick input.jpg &lt;span class="nt"&gt;-resize&lt;/span&gt; 1600x &lt;span class="nt"&gt;-strip&lt;/span&gt; &lt;span class="nt"&gt;-quality&lt;/span&gt; 80 output.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One gotcha: recompressing a JPEG that's already been compressed often saves little or nothing, and can even produce a bigger file. If a tool reports zero savings, it's usually because the image was already optimized. Always work from the original where you can.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Strip Metadata
&lt;/h2&gt;

&lt;p&gt;Photos carry metadata, known as EXIF data: camera model, lens settings, timestamps and, very often on phones, &lt;strong&gt;GPS coordinates&lt;/strong&gt;. Publishing a photo taken at someone's home can publish where they live. Stripping metadata removes that risk and shaves off some bytes.&lt;/p&gt;

&lt;p&gt;Two things to keep in mind. First, keep or convert the color profile, ideally to sRGB, so colors look the same in every browser. Second, apply the EXIF orientation &lt;em&gt;before&lt;/em&gt; stripping, or portrait photos can suddenly appear sideways. sharp removes metadata by default, and its &lt;code&gt;.rotate()&lt;/code&gt; method (with no arguments) applies the orientation first, which is why it appears in every example here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Automate It With a Pre-Upload Script
&lt;/h2&gt;

&lt;p&gt;Doing all of this by hand works for one image. For a whole site, put it in a script. Here's the one I use. It takes a folder of original JPEG and PNG files and, for each one, writes several widths in AVIF, WebP and JPEG, with metadata stripped, then prints a before-and-after report.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// scripts/optimize-images.mjs&lt;/span&gt;
&lt;span class="c1"&gt;// Usage: npm install sharp &amp;amp;&amp;amp; node scripts/optimize-images.mjs&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;sharp&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sharp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;readdir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stat&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:fs/promises&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SRC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;images-src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       &lt;span class="c1"&gt;// put your original images here&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;OUT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public/images&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;// optimized images go here&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;WIDTHS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;480&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;960&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1600&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;OUT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;recursive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;readdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SRC&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.(&lt;/span&gt;&lt;span class="sr"&gt;jpe&lt;/span&gt;&lt;span class="se"&gt;?&lt;/span&gt;&lt;span class="sr"&gt;g|png&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;$/i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SRC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;originalBytes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;originalWidth&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sharp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Never upscale: keep only widths the original can support&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;widths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;WIDTHS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;originalWidth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;widths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;widths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;originalWidth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;largestWebp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;widths&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sharp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;avif&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;quality&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;55&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;toFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;OUT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.avif`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;webp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;webp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;quality&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;toFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;OUT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.webp`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;jpeg&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;quality&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;mozjpeg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;toFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;OUT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.jpg`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="nx"&gt;largestWebp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;largestWebp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;webp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;kb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${(&lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; KB`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;kb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;originalBytes&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; original, largest WebP &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;kb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;largestWebp&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add it to your &lt;code&gt;package.json&lt;/code&gt; so anyone on the team can run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"images"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node scripts/optimize-images.mjs"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To stop oversized images from sneaking back in, add a size budget check to CI or a pre-commit hook. This one (Node 20 or newer) fails if any image in the output folder is over 300 KB:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// scripts/check-image-budget.mjs&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;readdir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stat&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:fs/promises&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DIR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public/images&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BUDGET_KB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;failed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;readdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DIR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;recursive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.(&lt;/span&gt;&lt;span class="sr"&gt;avif|webp|jpe&lt;/span&gt;&lt;span class="se"&gt;?&lt;/span&gt;&lt;span class="sr"&gt;g|png|gif&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;$/i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DIR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;BUDGET_KB&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; KB (budget: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;BUDGET_KB&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; KB)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;failed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;failed&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The budget number is a guideline, not a law. A full-width hero image might reasonably sit at 200 to 300 KB, while thumbnails should be a fraction of that. Adjust it to your site. The &lt;a href="https://sharp.pixelplumbing.com/" rel="noopener noreferrer"&gt;sharp documentation&lt;/a&gt; covers every option if you want to tune the output further.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Serve Images Properly
&lt;/h2&gt;

&lt;p&gt;Compression gets you halfway. The other half is making sure the browser downloads the right file at the right time. Here's a hero image using the files the script produced:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;picture&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/avif"&lt;/span&gt;
    &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"/images/hero-480.avif 480w, /images/hero-960.avif 960w, /images/hero-1600.avif 1600w"&lt;/span&gt;
    &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"(max-width: 1000px) 100vw, 1000px"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/webp"&lt;/span&gt;
    &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"/images/hero-480.webp 480w, /images/hero-960.webp 960w, /images/hero-1600.webp 1600w"&lt;/span&gt;
    &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"(max-width: 1000px) 100vw, 1000px"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/images/hero-960.jpg"&lt;/span&gt;
    &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"/images/hero-480.jpg 480w, /images/hero-960.jpg 960w, /images/hero-1600.jpg 1600w"&lt;/span&gt;
    &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"(max-width: 1000px) 100vw, 1000px"&lt;/span&gt;
    &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"1600"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"900"&lt;/span&gt;
    &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Team reviewing a website design on a large monitor"&lt;/span&gt;
    &lt;span class="na"&gt;fetchpriority=&lt;/span&gt;&lt;span class="s"&gt;"high"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/picture&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few details make a big difference:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The browser picks the first format it supports,&lt;/strong&gt; so list AVIF, then WebP, with JPEG as the fallback in the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;srcset&lt;/code&gt; and &lt;code&gt;sizes&lt;/code&gt; let the browser choose the right width&lt;/strong&gt; for the screen, so phones don't download desktop-sized images.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Always set &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt;.&lt;/strong&gt; The browser uses them to reserve space before the image loads, which prevents layout shift (CLS).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't lazy-load the hero image.&lt;/strong&gt; It's usually your LCP element, so it should load immediately, and &lt;code&gt;fetchpriority="high"&lt;/code&gt; tells the browser to prioritize it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do lazy-load images further down the page&lt;/strong&gt; with &lt;code&gt;loading="lazy"&lt;/code&gt; and &lt;code&gt;decoding="async"&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/images/gallery-960.webp"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"960"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"640"&lt;/span&gt;
  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Finished kitchen renovation with oak cabinets"&lt;/span&gt;
  &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt; &lt;span class="na"&gt;decoding=&lt;/span&gt;&lt;span class="s"&gt;"async"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Framework and Platform Shortcuts
&lt;/h2&gt;

&lt;p&gt;If you're on a modern framework, some of this is built in. Next.js's &lt;code&gt;&amp;lt;Image&amp;gt;&lt;/code&gt; component and Astro's &lt;code&gt;&amp;lt;Image /&amp;gt;&lt;/code&gt; both resize, convert formats and add &lt;code&gt;srcset&lt;/code&gt; automatically. Image CDNs can transform images on the fly through URL parameters.&lt;/p&gt;

&lt;p&gt;They're great, and you should use them. But it's still worth compressing your source files first. Smaller sources mean a lighter repository, faster builds and less work at request time.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Simple Version for Content Editors
&lt;/h2&gt;

&lt;p&gt;Scripts are great for developers, but on most teams, the people uploading images are marketers, writers and clients working in a CMS. If that's your situation, give them a simpler version of the workflow. Here's a checklist you can paste into your team's docs on how to compress images for a website before uploading:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Resize first.&lt;/strong&gt; Crop and resize the image to roughly the width it will appear on the page. For a blog post body, around 1,200 to 1,600 pixels wide is usually plenty. Most laptops have a built-in tool for this, such as Preview on a Mac or Photos on Windows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compress it.&lt;/strong&gt; Run it through an online compressor, and check the result looks right before you upload.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use a sensible file name.&lt;/strong&gt; Rename &lt;code&gt;IMG_4823.jpg&lt;/code&gt; to something descriptive, like &lt;code&gt;oak-kitchen-cabinets.jpg&lt;/code&gt;. It helps image search and keeps the media library tidy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write alt text in the CMS.&lt;/strong&gt; Describe what the image shows, in a short sentence, for people using screen readers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never upload straight from a phone or camera.&lt;/strong&gt; Those files are almost always far bigger than a website needs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It takes an extra minute per image, and it prevents the 4 MB hero photo problem entirely. If you can, back it up with the size budget check from Step 5, so anything that slips through gets caught before it goes live.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Check Your Results
&lt;/h2&gt;

&lt;p&gt;After deploying, verify it worked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lighthouse and PageSpeed Insights&lt;/strong&gt; flag image problems directly. Look for "Properly size images," "Serve images in next-gen formats" and "Efficiently encode images."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The DevTools Network panel&lt;/strong&gt; shows exactly what's downloaded. Filter by "Img," sort by size and check which format and width each image actually served.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A site-wide check&lt;/strong&gt; catches oversized images on pages you haven't looked at in a while. A quick &lt;a href="https://seositechecker.pro/website-seo-score-checker" rel="noopener noreferrer"&gt;site-wide SEO audit&lt;/a&gt; flags heavy images alongside other performance and SEO issues.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Recompressing the same JPEG over and over instead of working from the original.&lt;/li&gt;
&lt;li&gt;Lazy-loading the hero image, which delays LCP.&lt;/li&gt;
&lt;li&gt;Using PNG for photos.&lt;/li&gt;
&lt;li&gt;Leaving out &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt;, which causes layout shift.&lt;/li&gt;
&lt;li&gt;Shrinking giant images with CSS instead of resizing the file.&lt;/li&gt;
&lt;li&gt;Serving AVIF or WebP with no fallback for older clients.&lt;/li&gt;
&lt;li&gt;Exporting every screenshot at full Retina resolution, even thumbnails.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How do I compress images without losing quality?
&lt;/h3&gt;

&lt;p&gt;Use lossless compression (PNG or lossless WebP) when the image must be pixel-perfect. For photos, use lossy JPEG, WebP or AVIF at moderate quality settings, around 75 to 85 for JPEG and WebP. Some data is discarded, but at those settings the difference is usually invisible.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the best image format for websites?
&lt;/h3&gt;

&lt;p&gt;For most photos and graphics, WebP is the best all-round choice, with AVIF as an even smaller option where you can provide a fallback. Use SVG for logos and icons, JPEG as a universal fallback, and PNG only when you need lossless quality or transparency.&lt;/p&gt;

&lt;h3&gt;
  
  
  What file size should website images be?
&lt;/h3&gt;

&lt;p&gt;There's no single rule, but as a guideline, aim for most content images to be under 100 to 200 KB and large hero images under about 300 KB. Thumbnails should be far smaller. Resizing to the displayed dimensions usually does more than compression alone.&lt;/p&gt;

&lt;h3&gt;
  
  
  What dimensions should images be for a website?
&lt;/h3&gt;

&lt;p&gt;Match the largest size the image will actually display, and go up to 2x for important images on high-density screens. For full-width hero images, around 1,600 to 2,000 pixels wide is plenty. Generate several widths and let &lt;code&gt;srcset&lt;/code&gt; serve the right one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does compressing images help SEO?
&lt;/h3&gt;

&lt;p&gt;Indirectly, yes. Smaller images make pages load faster, which improves user experience and Core Web Vitals, especially Largest Contentful Paint. Google uses page experience as one of many signals. Descriptive file names and alt text also help your images appear in image search.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's the difference between lossy and lossless compression?
&lt;/h3&gt;

&lt;p&gt;Lossless compression stores exactly the same pixels more efficiently, so there's no quality loss, but savings are smaller. Lossy compression permanently discards some data, producing much smaller files. At sensible settings, lossy compression is usually indistinguishable from the original to the human eye.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Resize first, pick the right format, compress with sensible settings, strip the metadata, then serve the result with &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;, &lt;code&gt;srcset&lt;/code&gt; and proper loading hints. Put the whole thing in a script and a CI check, and "properly size images" disappears from your Lighthouse reports for good. For anything outside that workflow, there's a collection of &lt;a href="https://seositechecker.pro/tools" rel="noopener noreferrer"&gt;other free web tools&lt;/a&gt; for quick one-off jobs.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>performance</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Meta Tags That Matter: A Developer's Guide to Title and Description Tags</title>
      <dc:creator>Jay Barker</dc:creator>
      <pubDate>Thu, 22 Oct 2026 01:06:00 +0000</pubDate>
      <link>https://dev.to/jaybarker/meta-tags-that-matter-a-developers-guide-to-title-and-description-tags-odf</link>
      <guid>https://dev.to/jaybarker/meta-tags-that-matter-a-developers-guide-to-title-and-description-tags-odf</guid>
      <description>&lt;p&gt;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 &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; just quietly fell back to a default, on thousands of pages.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; I work with the team behind SEO Site Checker, whose meta tag analyzer I mention below. Everything else in this guide is tool-agnostic.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Short Version
&lt;/h2&gt;

&lt;p&gt;If you only read one section, make it this one:&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Which Meta Tags Actually Matter in 2026
&lt;/h2&gt;

&lt;p&gt;There are dozens of possible &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; tags. Very few of them change anything. Here's the shortlist:&lt;/p&gt;

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

&lt;p&gt;Strictly speaking, canonical and hreflang are &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; elements, not meta tags, but every audit checks them alongside the rest, so I've included them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Title Tags: What Google Actually Does With Them
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Google builds "title links," and your title tag is only one input
&lt;/h3&gt;

&lt;p&gt;The first thing to understand is that Google doesn't simply display your &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt;. It generates what it calls a title link, and &lt;a href="https://developers.google.com/search/docs/appearance/title-link" rel="noopener noreferrer"&gt;Google's documentation on title links&lt;/a&gt; lists the sources it can draw from: the &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; element, the main visible heading, &lt;code&gt;og:title&lt;/code&gt;, other large and prominent text on the page, anchor text, and the text of links pointing to the page.&lt;/p&gt;

&lt;p&gt;In practice, your title tag still wins most of the time. &lt;a href="https://ahrefs.com/blog/title-tags-study" rel="noopener noreferrer"&gt;Ahrefs' study of 953,276 title tags&lt;/a&gt; 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 &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; and your H1 disagree, Google may pick the H1.&lt;/p&gt;

&lt;h3&gt;
  
  
  Length is about pixels, not characters
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing rules that survive rewrites
&lt;/h3&gt;

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

&lt;h3&gt;
  
  
  Why Google rewrites your title
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  A template pattern that works
&lt;/h3&gt;

&lt;p&gt;Here's a small title builder with sensible fallbacks. It tries the most specific version first and drops segments until the title fits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BRAND&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Acme Tools&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MAX_LENGTH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;buildTitle&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;section&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;candidates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;section&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BRAND&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BRAND&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; | &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;MAX_LENGTH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Last resort: trim the page name at a word boundary&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lastIndexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MAX_LENGTH&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;buildTitle&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cordless Drill 18V&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;section&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Power Tools&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// "Cordless Drill 18V | Power Tools | Acme Tools"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Meta Descriptions: Do They Still Matter?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Google rewrites most of them, so write them anyway
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;So why bother? Because when your description &lt;em&gt;is&lt;/em&gt; 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. &lt;a href="https://developers.google.com/search/docs/appearance/snippet" rel="noopener noreferrer"&gt;Google's guidance on meta descriptions&lt;/a&gt; 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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Length
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing rules
&lt;/h3&gt;

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

&lt;h3&gt;
  
  
  Generating them programmatically
&lt;/h3&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stripHtml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&amp;lt;&lt;/span&gt;&lt;span class="se"&gt;[^&lt;/span&gt;&lt;span class="sr"&gt;&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&amp;gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;truncate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lastIndexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;…&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;productDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; by &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;brand&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s2"&gt;`from $&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keyBenefit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Too thin? Fall back to a cleaned excerpt of the product copy&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;stripHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;truncate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;160&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Implementing Meta Tags in Your Stack
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Plain HTML
&lt;/h3&gt;

&lt;p&gt;For reference, here's a complete, correct &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; for a typical page. Note that &lt;code&gt;charset&lt;/code&gt; comes first, within the first 1024 bytes of the document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Cordless Drill 18V | Power Tools | Acme Tools&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Lightweight 18V cordless drill with two batteries and a 3-year warranty. Free shipping on orders over $50."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"canonical"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/products/cordless-drill-18v"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Cordless Drill 18V | Acme Tools"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Lightweight 18V cordless drill with two batteries and a 3-year warranty."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/images/drill-og.jpg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:card"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"summary_large_image"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Next.js App Router
&lt;/h3&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/layout.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;metadataBase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Acme Tools&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;%s | Acme Tools&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Quality power tools with free shipping on orders over $50.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then generate page-specific metadata for dynamic routes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/products/[slug]/page.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateMetadata&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Metadata&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// becomes "Cordless Drill 18V | Acme Tools"&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;alternates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;canonical&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`/products/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;openGraph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because this runs on the server, the tags are in the initial HTML response, which is exactly where you want them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Astro and other static site generators
&lt;/h3&gt;

&lt;p&gt;With Astro, a shared SEO component keeps every page consistent. Each page passes props from its front matter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
// 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);
---
&amp;lt;title&amp;gt;{fullTitle}&amp;lt;/title&amp;gt;
&amp;lt;meta name="description" content={description} /&amp;gt;
&amp;lt;link rel="canonical" href={canonical} /&amp;gt;
&amp;lt;meta property="og:title" content={fullTitle} /&amp;gt;
&amp;lt;meta property="og:description" content={description} /&amp;gt;
&amp;lt;meta property="og:image" content={new URL(image, Astro.site)} /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same pattern works in Hugo, Eleventy or any template engine: one component, required props and no silent defaults.&lt;/p&gt;

&lt;h3&gt;
  
  
  Single-page apps and client-side rendering
&lt;/h3&gt;

&lt;p&gt;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 &lt;code&gt;index.html&lt;/code&gt;. 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.&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;curl&lt;/code&gt;. If the right title isn't in that response, it isn't really there.&lt;/p&gt;

&lt;h3&gt;
  
  
  CMS templates and fallbacks
&lt;/h3&gt;

&lt;p&gt;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 &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt;, and never fall back to one site-wide description on every page. Both turn into duplicate-content warnings at scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Other Meta Tags Developers Break
&lt;/h2&gt;

&lt;p&gt;A few more tags cause outsized damage when they go wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;noindex&lt;/code&gt; left on from staging.&lt;/strong&gt; Check both the &lt;code&gt;&amp;lt;meta name="robots"&amp;gt;&lt;/code&gt; tag and the &lt;code&gt;X-Robots-Tag&lt;/code&gt; HTTP header. The header version is often set at the server or CDN level and won't show in your page source.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A missing or wrong &lt;code&gt;viewport&lt;/code&gt;.&lt;/strong&gt; Without it, mobile browsers render a zoomed-out desktop layout.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Charset declared too late.&lt;/strong&gt; If &lt;code&gt;&amp;lt;meta charset&amp;gt;&lt;/code&gt; isn't near the top of the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;, browsers may guess the encoding and mangle special characters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Broken Open Graph images.&lt;/strong&gt; 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Canonicals pointing to the wrong place.&lt;/strong&gt; A canonical that points to a redirect, a 404 or the homepage tells Google to ignore the page you actually want indexed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to Test Your Meta Tags
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Use a meta tag analyzer for a quick check
&lt;/h3&gt;

&lt;p&gt;For a fast, visual check of any public URL, a &lt;a href="https://seositechecker.pro/meta-tag-analyzer" rel="noopener noreferrer"&gt;free meta tag analyzer&lt;/a&gt; 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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check the raw response with curl and DevTools
&lt;/h3&gt;

&lt;p&gt;For the ground truth, look at exactly what the server sends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Title, description, robots and Open Graph tags in the raw HTML&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://example.com/products/cordless-drill-18v &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-iE&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;title&amp;gt;|name="description"|name="robots"|property="og:'&lt;/span&gt;

&lt;span class="c"&gt;# The X-Robots-Tag header, which won't show in the page source&lt;/span&gt;
curl &lt;span class="nt"&gt;-sI&lt;/span&gt; https://example.com/products/cordless-drill-18v | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; x-robots-tag
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automate it in CI
&lt;/h3&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// scripts/check-meta.mjs&lt;/span&gt;
&lt;span class="c1"&gt;// Usage: node scripts/check-meta.mjs https://staging.example.com/ https://staging.example.com/products/sample&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;urls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;seenTitles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;failed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`FAIL &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nx"&gt;failed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getMeta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;meta&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;s+name=["']&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;["']&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;s+content=["']([^"']*)["']`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;i&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))?.[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&amp;lt;title&lt;/span&gt;&lt;span class="se"&gt;[^&lt;/span&gt;&lt;span class="sr"&gt;&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;([^&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;title&amp;gt;/i&lt;/span&gt;&lt;span class="p"&gt;)?.[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getMeta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;robots&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;getMeta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;robots&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-robots-tag&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;missing &amp;lt;title&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`title is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; characters`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;seenTitles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`duplicate title, also on &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;seenTitles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;seenTitles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;missing meta description&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/noindex/i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;robots&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;noindex found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;failed&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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 &lt;code&gt;cheerio&lt;/code&gt;. Run it against staging after each deploy, and point it at production URLs too, to catch a stray &lt;code&gt;noindex&lt;/code&gt; before Google does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes Checklist
&lt;/h2&gt;

&lt;p&gt;Paste this into a PR description or a ticket and tick it off for every new template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; [ ] Every template outputs a unique &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;, around 50 to 60 characters
&lt;span class="p"&gt;-&lt;/span&gt; [ ] &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt; and H1 describe the same thing
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Brand name at the end of titles, not the start (except the homepage)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] No duplicate titles on paginated or filtered pages
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Unique meta description on every important page
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Meta tags present in the server HTML, not injected client-side
&lt;span class="p"&gt;-&lt;/span&gt; [ ] No noindex in meta tags or X-Robots-Tag headers on production
&lt;span class="p"&gt;-&lt;/span&gt; [ ] viewport and charset set correctly, with charset near the top of &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Canonical points to the correct, indexable URL
&lt;span class="p"&gt;-&lt;/span&gt; [ ] og:title, og:description and an absolute og:image URL present
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want the wider list beyond meta tags, this &lt;a href="https://seositechecker.pro/seo-checks" rel="noopener noreferrer"&gt;full reference of SEO checks&lt;/a&gt; explains each one and how to fix a failing result.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is a meta tag analyzer?
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  How long should a title tag be?
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  How long should a meta description be?
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does Google still use meta descriptions?
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do meta keywords still matter for SEO?
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why is Google showing a different title than my title tag?
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;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."&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>seo</category>
      <category>html</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Best Free Website Builders in 2026, Compared</title>
      <dc:creator>Jay Barker</dc:creator>
      <pubDate>Wed, 21 Oct 2026 01:00:00 +0000</pubDate>
      <link>https://dev.to/jaybarker/best-free-website-builders-in-2026-compared-2cch</link>
      <guid>https://dev.to/jaybarker/best-free-website-builders-in-2026-compared-2cch</guid>
      <description>&lt;p&gt;If you write code for a living, you already know this request. A cousin opening a bakery, a friend running a yoga class, a neighbor organizing a charity 5K. They all want "a quick free website," and they all assume you'll build it this weekend.&lt;/p&gt;

&lt;p&gt;Sometimes you should. Most of the time, a good free website builder is the better answer, because they can run it themselves and you don't become their unpaid web host for the next five years.&lt;/p&gt;

&lt;p&gt;The problem is that "free" means very different things depending on the builder. Some free plans plaster ads across your site. Some cap you at two pages. Some are really 14-day trials wearing a free plan costume. So I went through the options that matter in 2026 and wrote down what each one actually gives you, what the catch is, and what it costs to upgrade when "free" stops being enough. This is the list I now send people instead of agreeing to build their site.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; I work with the team behind Sitelyx, one of the builders on this list. I've tried to rank it where it honestly fits and to be upfront about its limits, the same way I've treated everything else here.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Quick Picks
&lt;/h2&gt;

&lt;p&gt;If you just want the answer, here it is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best overall:&lt;/strong&gt; Wix&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best for blogging:&lt;/strong&gt; WordPress.com&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best for design control:&lt;/strong&gt; Webflow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best for no-fuss project, school or event sites:&lt;/strong&gt; Google Sites&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best for selling products for free:&lt;/strong&gt; Square Online&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cheapest upgrade to a custom domain:&lt;/strong&gt; Sitelyx&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best for single-page sites:&lt;/strong&gt; Carrd&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best for developers:&lt;/strong&gt; a static site on GitHub Pages or Cloudflare Pages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now for the details, starting with the fine print nobody puts on the landing page.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "Free" Really Means
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Free plan vs free trial
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;free plan&lt;/strong&gt; has no end date. You can run a site on it for years without paying. A &lt;strong&gt;free trial&lt;/strong&gt; gives you the full product for a limited time, usually 14 days, and then your site goes offline unless you pay. Squarespace and Hostinger's website builder are both great products, but they offer trials or money-back guarantees rather than permanent free plans, so they aren't on this list.&lt;/p&gt;

&lt;p&gt;Everything below has a real, permanent free plan, or is genuinely free to host.&lt;/p&gt;

&lt;h3&gt;
  
  
  The usual catches
&lt;/h3&gt;

&lt;p&gt;Free plans are a marketing funnel, and the limits are designed to push you toward upgrading. Here's what to look out for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Branding or ads on your site.&lt;/strong&gt; Usually a banner or footer badge, and sometimes actual third-party ads shown to your visitors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A subdomain instead of your own domain.&lt;/strong&gt; Your address looks like &lt;code&gt;yourname.wixsite.com&lt;/code&gt; instead of &lt;code&gt;yourname.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage and bandwidth caps.&lt;/strong&gt; Fine for a few pages, tight once you add photo galleries or video.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Page or post limits.&lt;/strong&gt; Some free plans cap you at a handful of pages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No ecommerce, or fees on every sale.&lt;/strong&gt; Selling is the most common thing locked behind a paywall.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limited SEO controls and analytics.&lt;/strong&gt; Harder to show up on Google and harder to know who's visiting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No custom email.&lt;/strong&gt; You can't get &lt;code&gt;hello@yourbusiness.com&lt;/code&gt; on a free plan.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these are dealbreakers for a hobby site or a quick event page. For a real business, a few of them matter a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Compared Them
&lt;/h2&gt;

&lt;p&gt;I looked at each builder through the same lens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free plan limits.&lt;/strong&gt; Pages, storage, bandwidth and branding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ease of use.&lt;/strong&gt; Could a non-technical person build and update a site without calling me?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design flexibility.&lt;/strong&gt; How far can you push a template before it fights back?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blogging and SEO basics.&lt;/strong&gt; Editable titles and descriptions, clean URLs and a decent blog editor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ecommerce on the free plan.&lt;/strong&gt; Can you sell anything without paying?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upgrade cost.&lt;/strong&gt; What it costs to remove the branding and connect your own domain. In my experience, this is the number that actually matters, because almost everyone upgrades eventually.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lock-in.&lt;/strong&gt; Can you export your content if you leave?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One important caveat: free plan limits and prices change often. Every figure here was checked at the time of writing, but confirm the current details on each builder's own pricing page before you commit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Best Free Website Builders in 2026
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Wix: Best overall
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; small businesses, creatives and anyone who wants maximum design freedom without touching code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the free plan includes:&lt;/strong&gt; the full drag-and-drop editor, hundreds of templates, hosting and 500 MB of storage. There's no time limit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The catch:&lt;/strong&gt; a Wix banner sits on your site, your address is a &lt;code&gt;wixsite.com&lt;/code&gt; subdomain, and you can't sell anything. The editor's freedom also cuts both ways. It's easy for non-designers to create a cluttered page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cheapest upgrade:&lt;/strong&gt; the Light plan runs about $17 a month billed annually and adds a custom domain without the Wix banner, but it still doesn't let you sell. To take payments, you need Core, at about $29 a month billed annually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verdict:&lt;/strong&gt; the safest all-round recommendation for non-technical friends. Just be clear with them that the free plan is a starting point, not a business site.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. WordPress.com: Best for blogging
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; writers, bloggers and anyone whose site is mostly articles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the free plan includes:&lt;/strong&gt; WordPress's excellent block editor, free themes, hosting and 1 GB of storage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The catch:&lt;/strong&gt; WordPress.com shows ads to your visitors on the free plan, you're on a &lt;code&gt;wordpress.com&lt;/code&gt; subdomain, and you can't install plugins. Also, a quick note on naming: WordPress.com is a hosted service, while WordPress.org is the free open-source software you install on your own hosting. They share a name, but the free WordPress.com plan is far more limited than self-hosted WordPress.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cheapest upgrade:&lt;/strong&gt; the Personal plan is about $4 a month billed annually ($48 for the year) or $9 billed monthly, and removes ads and adds a custom domain. Annual billing also includes a free domain for the first year.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verdict:&lt;/strong&gt; the best free home for a blog, and the upgrade path is one of the cheapest on this list.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Webflow: Best for design control
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; designers and developers who want a visual builder that thinks in real HTML and CSS, with classes, flexbox, grid and a proper CMS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the free plan includes:&lt;/strong&gt; the full designer, two static pages, a CMS with up to 50 items, 1 GB of bandwidth and a &lt;code&gt;webflow.io&lt;/code&gt; subdomain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The catch:&lt;/strong&gt; the Webflow badge appears on free sites, two pages is very tight, and there's no custom domain. The learning curve is also much steeper than Wix. Hand Webflow to a non-technical client and they'll call you within the week.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cheapest upgrade:&lt;/strong&gt; the Basic site plan, at roughly $14 to $15 a month, gets you a custom domain for a simple site without a CMS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verdict:&lt;/strong&gt; the best free option for learning and prototyping, and a great tool if you want visual building without giving up structure. Not the one to give your cousin's bakery.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Google Sites: Best for no-fuss project sites
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; school projects, internal team pages, event sites, wedding pages and documentation for small groups.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the free plan includes:&lt;/strong&gt; everything. Google Sites is completely free with any Google account, shows no ads and integrates neatly with Docs, Sheets, Slides and Calendar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The catch:&lt;/strong&gt; design options are basic, there's no real blog, and SEO controls are minimal. It's built for sharing information, not for winning customers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cheapest upgrade:&lt;/strong&gt; there isn't one, because it's already free. You can even connect a custom domain from a personal Google account. Verify the domain in Google Search Console, add a CNAME record pointing to &lt;code&gt;ghs.googlehosted.com&lt;/code&gt;, then assign it in the site's settings. It has to be a subdomain, like &lt;code&gt;www.yourdomain.com&lt;/code&gt;, rather than the bare root domain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verdict:&lt;/strong&gt; the most genuinely free option on the list. Perfect when the goal is "get this information online today," and wrong for anything that needs to sell.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Square Online: Best for selling for free
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; small shops, makers and restaurants that want to take orders without paying a monthly fee.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the free plan includes:&lt;/strong&gt; an ecommerce site with product listings, online ordering for food businesses and a booking site for appointment-based businesses, all on a Square-hosted subdomain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The catch:&lt;/strong&gt; you pay on every sale instead of every month. On the free plan, online transactions cost 3.3% plus 30 cents. Square branding appears on free sites, and design options are more limited than a general-purpose builder.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cheapest upgrade:&lt;/strong&gt; Square restructured its plans in 2025. Its all-in-one Plus plan is about $49 a month and lowers the online rate to 2.9% plus 30 cents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verdict:&lt;/strong&gt; if a friend wants to sell something next week and has no budget, this is the answer. The per-sale fee is easy to live with at low volume.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Sitelyx: Cheapest upgrade to a custom domain
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; small businesses, freelancers and side projects that need a few proper pages and a blog, and want a custom domain without a big monthly bill.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the free plan includes:&lt;/strong&gt; one website with a &lt;code&gt;yourname.sitelyx.co&lt;/code&gt; subdomain, all 18 niche templates, up to 5 pages and 5 blog posts, SSL, a contact form, basic analytics, plus blog, portfolio, donation and event modules. There's no time limit, and you don't need a credit card to start.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[EDITOR: confirm whether free Sitelyx sites show a Sitelyx badge or ads, and add one sentence here before publishing.]&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The catch:&lt;/strong&gt; the free plan caps you at 5 pages and 5 posts, and it doesn't include ecommerce. Sitelyx is also a newer builder, so its template library and community are much smaller than Wix or WordPress, and you'll find fewer tutorials and third-party integrations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cheapest upgrade:&lt;/strong&gt; this is where it stands out. The Growth plan is $4 a month and adds a custom domain, up to 20 pages, and booking modules for appointments, restaurants and events, along with Stripe and PayPal payment gateways. The Pro plan, at $6 a month, adds ecommerce and point of sale with no Sitelyx commission on sales. Payment processor fees still apply. Paid plans come with a 10-day free trial, and you can see the full breakdown of &lt;a href="https://sitelyx.co/pricing-plan" rel="noopener noreferrer"&gt;Sitelyx's free and paid plans&lt;/a&gt; on its pricing page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verdict:&lt;/strong&gt; if the budget question is "what's the cheapest way to get a real business site on my own domain," Sitelyx is hard to beat. You can &lt;a href="https://sitelyx.co/all-templates" rel="noopener noreferrer"&gt;browse the 18 Sitelyx templates&lt;/a&gt; to see whether one fits your niche before you sign up. If you need a huge app marketplace or advanced design freedom, Wix or Webflow are the better fit.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Carrd: Best for single-page sites
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; personal pages, link-in-bio pages, portfolios, landing pages and "coming soon" pages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the free plan includes:&lt;/strong&gt; up to three published single-page sites on a Carrd subdomain, with a clean editor that's genuinely hard to make look bad.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The catch:&lt;/strong&gt; every site is one page, a "Made with Carrd" footer appears on free sites, and there's no custom domain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cheapest upgrade:&lt;/strong&gt; this is the cheapest upgrade on the list. Pro Standard costs $19 a year and adds custom domains for up to 10 sites. (Pro Lite, at $9 a year, doesn't include custom domains.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verdict:&lt;/strong&gt; if one page is all you need, Carrd is the best tool for the job. Developers love it for side projects, and so do I.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Strikingly: Good for simple one-page stores
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; single-page sites that need a little selling, like a product launch or a small personal brand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the free plan includes:&lt;/strong&gt; one scrolling page, 500 MB of storage, 5 GB of bandwidth and a Strikingly subdomain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The catch:&lt;/strong&gt; Strikingly branding appears on free sites, and selling is limited to a single product. The one-page format suits landing pages but gets awkward for businesses with lots of services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cheapest upgrade:&lt;/strong&gt; paid plans add a custom domain, more pages and more products. Prices vary by billing term, so check the current plans before you choose.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verdict:&lt;/strong&gt; a decent middle ground between Carrd and a full builder, especially if you want to sell one thing on one page.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. SITE123: Easiest for complete beginners
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; people who've never built a website and want the most hand-holding possible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the free plan includes:&lt;/strong&gt; a guided setup that asks a few questions and builds a site for you, with hosting on a &lt;code&gt;site123.me&lt;/code&gt; subdomain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The catch:&lt;/strong&gt; the free plan is tight, with 250 MB of storage and 250 MB of bandwidth. A SITE123 banner appears on free sites, and the structured approach means less design freedom than Wix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cheapest upgrade:&lt;/strong&gt; the Premium plan adds a custom domain and removes the banner. The price depends on billing length, so compare terms before paying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verdict:&lt;/strong&gt; a solid choice for the least technical person you know. Anyone with a little confidence will outgrow it quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Developer Route: Truly Free Hosting
&lt;/h2&gt;

&lt;p&gt;If you're comfortable with Git and a terminal, there's an option that beats every free plan above on the things that matter: no ads, your own domain, HTTPS and great performance, all for $0.&lt;/p&gt;

&lt;h3&gt;
  
  
  Static site generators
&lt;/h3&gt;

&lt;p&gt;A static site generator turns Markdown files and templates into plain HTML at build time. There's no database to secure and no server-side code to patch, and the output loads fast. Astro, Hugo and Eleventy are all excellent choices. Astro is especially friendly if you already know modern JavaScript, and &lt;a href="https://docs.astro.build/" rel="noopener noreferrer"&gt;Astro's documentation&lt;/a&gt; has starter templates for blogs, portfolios and docs sites.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub Pages
&lt;/h3&gt;

&lt;p&gt;GitHub Pages serves a static site straight from a repository, for free. You can connect a custom domain and enforce HTTPS, and every push updates the site. It only hosts static content, so anything dynamic like forms or comments needs a third-party service. The &lt;a href="https://docs.github.com/en/pages" rel="noopener noreferrer"&gt;GitHub Pages docs&lt;/a&gt; walk you through setup in a few minutes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloudflare Pages and Netlify
&lt;/h3&gt;

&lt;p&gt;Both offer generous free tiers that build your site automatically on every push. You also get preview deployments for every branch, a global CDN and custom domains with HTTPS. &lt;a href="https://developers.cloudflare.com/pages/" rel="noopener noreferrer"&gt;Cloudflare Pages&lt;/a&gt; is particularly strong on bandwidth limits and speed, while Netlify's free tier includes a simple form-handling service that's handy for contact forms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The honest catch:&lt;/strong&gt; this route is free for &lt;em&gt;you&lt;/em&gt;, but not for the person you're building it for. There's no visual editor, so every content change means a commit. For your own portfolio or blog, it's the best free option there is. For your cousin's bakery, it means you're on call forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  What About AI Website Builders?
&lt;/h2&gt;

&lt;p&gt;In 2026, almost every builder on this list has added some kind of AI feature. Typically, you describe your business in a sentence or two, and the builder generates a layout, picks colors, writes placeholder copy and suggests images. Some standalone tools now build an entire site from a single prompt.&lt;/p&gt;

&lt;p&gt;These features are genuinely useful for getting past a blank page. A rough first draft in two minutes beats an hour of staring at templates. But I'd treat them as a starting point, not a finished site, for three reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The copy is generic.&lt;/strong&gt; AI-written text tends to sound like every other small business website. Your real story, real photos and real customer details are what make visitors trust you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The facts need checking.&lt;/strong&gt; AI tools sometimes invent services, opening hours or claims you don't actually offer. Read every line before you publish.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The free tiers are limited.&lt;/strong&gt; Many builders cap AI generations on free plans or keep the best AI features for paid tiers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My advice is to let the AI build the skeleton, then rewrite the words yourself. It takes an extra hour and makes the site sound like a real person runs it, which is exactly what visitors are looking for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Side-by-Side Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Builder&lt;/th&gt;
&lt;th&gt;Free storage&lt;/th&gt;
&lt;th&gt;Branding or ads on free plan&lt;/th&gt;
&lt;th&gt;Custom domain on free plan&lt;/th&gt;
&lt;th&gt;Sell on free plan&lt;/th&gt;
&lt;th&gt;Cheapest upgrade with a custom domain&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Wix&lt;/td&gt;
&lt;td&gt;500 MB&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;About $17/month (annual)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WordPress.com&lt;/td&gt;
&lt;td&gt;1 GB&lt;/td&gt;
&lt;td&gt;Yes (ads)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;About $4/month (annual)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Webflow&lt;/td&gt;
&lt;td&gt;1 GB bandwidth, 2 pages&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;About $14 to $15/month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Sites&lt;/td&gt;
&lt;td&gt;Google account storage&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Square Online&lt;/td&gt;
&lt;td&gt;Not capped&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (3.3% + 30¢ per sale)&lt;/td&gt;
&lt;td&gt;About $49/month (Plus)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sitelyx&lt;/td&gt;
&lt;td&gt;5 pages, 5 posts&lt;/td&gt;
&lt;td&gt;Confirm before publishing&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;$4/month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Carrd&lt;/td&gt;
&lt;td&gt;3 one-page sites&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;$19/year&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strikingly&lt;/td&gt;
&lt;td&gt;500 MB, 1 page&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;1 product&lt;/td&gt;
&lt;td&gt;Varies by term&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SITE123&lt;/td&gt;
&lt;td&gt;250 MB&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Varies by term&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Pages / Cloudflare Pages&lt;/td&gt;
&lt;td&gt;Static sites&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How to Pick the Right Free Builder
&lt;/h2&gt;

&lt;p&gt;Match the tool to the job:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"I need this online today for an event or a project."&lt;/strong&gt; Use Google Sites.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"I want to start a blog."&lt;/strong&gt; Use WordPress.com.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"I want a good-looking business site that can grow."&lt;/strong&gt; Use Wix, or Sitelyx if keeping the monthly cost low matters most.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"I want to sell products without a monthly fee."&lt;/strong&gt; Use Square Online.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"I just need one page."&lt;/strong&gt; Use Carrd.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"I want full creative control and I'm willing to learn."&lt;/strong&gt; Use Webflow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"I'm comfortable with Git."&lt;/strong&gt; Build a static site and host it on GitHub Pages or Cloudflare Pages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're helping someone else, add one more question: who will update the site after launch? If the answer is them, pick something with a visual editor they'll actually enjoy using.&lt;/p&gt;

&lt;h2&gt;
  
  
  When You Should Upgrade
&lt;/h2&gt;

&lt;p&gt;Free plans are great for testing an idea, building a portfolio or getting a hobby project online. But there are a few clear signs it's time to pay:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You're using the site for a real business.&lt;/strong&gt; A custom domain and the absence of someone else's branding make an immediate difference to trust.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You need to take payments,&lt;/strong&gt; and per-sale fees on a free plan are starting to add up.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You've hit the page, post or storage limits.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You want a professional email address&lt;/strong&gt; on your own domain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My rule of thumb is simple: the cheapest plan that adds a custom domain is usually the only upgrade a small site needs. Everything above that is optional until you have a specific reason.&lt;/p&gt;

&lt;h2&gt;
  
  
  Watch Out for Lock-In
&lt;/h2&gt;

&lt;p&gt;Here's the part most comparison articles skip. With a hosted builder, you're renting, not owning. Your content lives on the builder's platform, in the builder's format, and moving it somewhere else later is rarely a one-click job.&lt;/p&gt;

&lt;p&gt;Before you commit, a few quick checks save a lot of pain later:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Can you export your content?&lt;/strong&gt; WordPress.com lets you export posts and pages in a standard format. Many drag-and-drop builders only let you copy content out by hand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Who owns the domain?&lt;/strong&gt; Register your domain with an independent registrar, or make sure you can transfer it out if the builder gives you one. Your domain is the one thing you should never lose.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where do your images live?&lt;/strong&gt; Keep the original photos on your own computer or cloud drive, not only inside the builder.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this means you should avoid hosted builders. It just means you should go in with your eyes open, and own the pieces that are hardest to replace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can a Free Website Rank on Google?
&lt;/h2&gt;

&lt;p&gt;Yes. Google indexes free sites, and they can rank. But free plans make it harder in a few ways. Subdomains build authority for the builder rather than for you, SEO controls are often limited, and the extra branding scripts can slow pages down.&lt;/p&gt;

&lt;p&gt;Whichever builder you pick, check the basics once your site is live: page titles, meta descriptions, mobile layout and loading speed. A &lt;a href="https://seositechecker.pro/website-seo-score-checker" rel="noopener noreferrer"&gt;free SEO audit&lt;/a&gt; will flag those issues in about a minute, which beats guessing why the site isn't showing up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Launch a Free Site or Blog in 30 Minutes
&lt;/h2&gt;

&lt;p&gt;If you're wondering how to start a blog for free, or just want any simple site live tonight, here's the fastest path:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pick a builder&lt;/strong&gt; from the decision guide above.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choose a template&lt;/strong&gt; that's close to what you want. Resist the urge to customize everything on day one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write three pages:&lt;/strong&gt; a homepage that says what you do, an about page and a contact page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish your first blog post,&lt;/strong&gt; even if it's short. A site with real content looks alive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check it on your phone,&lt;/strong&gt; connect basic analytics and share the link.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can polish the design later. Getting something real online is the step most people never take.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is there a truly free website builder?
&lt;/h3&gt;

&lt;p&gt;Yes. Google Sites is completely free with no ads, and static hosting on GitHub Pages or Cloudflare Pages costs nothing either. Most other builders offer permanent free plans with limits, such as branding on your site, a subdomain instead of your own domain, and restrictions on pages, storage or selling.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's the difference between a free plan and a free trial?
&lt;/h3&gt;

&lt;p&gt;A free plan has no end date, so you can keep your site online without paying, within its limits. A free trial gives you the full product for a limited time, usually around 14 days, and your site goes offline when it ends unless you choose a paid plan.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use my own domain with a free website builder?
&lt;/h3&gt;

&lt;p&gt;Usually not. Most free plans only give you a subdomain, like yourname.wixsite.com. The main exceptions are Google Sites, which supports custom domains for free, and static hosting on GitHub Pages or Cloudflare Pages. Elsewhere, a custom domain is usually the first thing you get when you upgrade.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do free website builders include hosting?
&lt;/h3&gt;

&lt;p&gt;Yes. Hosted builders like Wix, WordPress.com, Webflow, Google Sites, Square Online, Sitelyx, Carrd, Strikingly and SITE123 include hosting on their free plans, so you don't need to buy it separately. Self-hosted WordPress is different, because you install the software on hosting you pay for yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Will my free website show up on Google?
&lt;/h3&gt;

&lt;p&gt;It can. Google indexes free sites, and a free site with useful content can rank for specific searches. A subdomain, limited SEO controls and slower pages make it harder to compete, though. Write clear page titles, keep the site fast and mobile-friendly, and submit it to Google Search Console.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which free website builder is best for beginners?
&lt;/h3&gt;

&lt;p&gt;Wix and SITE123 are the most beginner-friendly. SITE123 builds a site for you from a few questions, while Wix gives you more freedom with a drag-and-drop editor. For a single-page site, Carrd is very easy, and Google Sites is the simplest of all for basic information pages.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I remove ads from a free website?
&lt;/h3&gt;

&lt;p&gt;On most builders, you remove ads or branding by upgrading to the cheapest paid plan. Prices range from about $19 a year on Carrd to about $4 a month on WordPress.com and Sitelyx, and more on Wix. Google Sites and static hosting on GitHub Pages or Cloudflare Pages never show ads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Free is a great place to start and a bad place to stay if you're running a business. Pick the builder that matches the job, know what the upgrade costs before you commit, and don't be afraid to start small. If you're the developer in the family, point people to the decision guide above, and save the static site setup for your own portfolio.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>nocode</category>
      <category>productivity</category>
    </item>
    <item>
      <title>A Practical SEO Audit Checklist for Developers</title>
      <dc:creator>Jay Barker</dc:creator>
      <pubDate>Tue, 20 Oct 2026 03:52:06 +0000</pubDate>
      <link>https://dev.to/jaybarker/a-practical-seo-audit-checklist-for-developers-2176</link>
      <guid>https://dev.to/jaybarker/a-practical-seo-audit-checklist-for-developers-2176</guid>
      <description>&lt;p&gt;Sooner or later, someone from marketing sends you an SEO report. It's a 40-page PDF full of red warnings, half of them duplicates, and none of them explain how to reproduce the problem. "Canonical issues detected." Which pages? Detected how? You close the PDF and go back to your sprint.&lt;/p&gt;

&lt;p&gt;I've been on the receiving end of that report more times than I'd like. So this is the SEO audit checklist I wish I'd had: every item comes with a way to verify it yourself (usually a &lt;code&gt;curl&lt;/code&gt; command or a DevTools panel) and a way to fix it.&lt;/p&gt;

&lt;p&gt;Here's the thing most SEO checklists skip. The problems that hurt rankings the most are usually code problems. A leftover &lt;code&gt;noindex&lt;/code&gt; header. A redirect chain from a framework migration. A hero image that takes four seconds to paint. Marketers can spot the symptoms, but developers are the ones who can find the cause and ship the fix.&lt;/p&gt;

&lt;p&gt;Let's go through it phase by phase.&lt;/p&gt;

&lt;h2&gt;
  
  
  What an SEO Audit Is (and Which Parts Developers Own)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The three layers of an audit
&lt;/h3&gt;

&lt;p&gt;An SEO audit is a structured review of everything that affects how a site performs in search. It usually covers three layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Technical SEO:&lt;/strong&gt; can search engines crawl, render and index your pages, and do those pages load fast?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On-page SEO:&lt;/strong&gt; are titles, headings, content and markup clear about what each page is about?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Off-page SEO:&lt;/strong&gt; how many trusted sites link to you, and what does your reputation look like across the web?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Where developers fit in
&lt;/h3&gt;

&lt;p&gt;Off-page work and most content decisions belong to the marketing side. But crawling, indexing, rendering, performance, markup and server configuration all live in your codebase. They also tend to break silently. Nobody files a bug when Googlebot stops indexing your product pages. Traffic just drifts down for three months until someone notices.&lt;/p&gt;

&lt;p&gt;That's the layer this checklist focuses on. If you get it right, the content team's work actually has a chance to rank.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Free Tool Stack You Need
&lt;/h2&gt;

&lt;p&gt;You don't need a paid SEO suite for any of this. Here's what I use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google Search Console.&lt;/strong&gt; The source of truth for how Google sees your site. The Pages report shows what's indexed and why the rest isn't, and the URL Inspection tool shows the HTML Googlebot actually rendered.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lighthouse.&lt;/strong&gt; Built into Chrome DevTools, and also available as a CLI for scripting and CI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PageSpeed Insights.&lt;/strong&gt; Runs Lighthouse, but more importantly shows field data from real Chrome users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A crawler.&lt;/strong&gt; Screaming Frog's free version crawls up to 500 URLs, which covers most small and mid-sized sites.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;curl&lt;/code&gt; and DevTools.&lt;/strong&gt; For headers, status codes, redirects and comparing raw HTML with the rendered DOM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google's Rich Results Test.&lt;/strong&gt; For validating structured data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A quick baseline report.&lt;/strong&gt; A &lt;a href="https://seositechecker.pro/website-seo-score-checker" rel="noopener noreferrer"&gt;free SEO audit tool&lt;/a&gt; gives you a scored snapshot of a page across on-page, speed and security checks in about a minute. It's handy for a first pass and for before-and-after comparisons.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Phase 0: Get a Baseline Before You Touch Anything
&lt;/h2&gt;

&lt;p&gt;Before fixing anything, record where you're starting from. Otherwise you'll have no way to prove your changes worked.&lt;/p&gt;

&lt;p&gt;The key idea is to &lt;strong&gt;audit templates, not pages&lt;/strong&gt;. Most sites are a handful of templates rendering thousands of URLs: homepage, listing or category page, detail page, blog post, maybe a search results page. A bug in the product template is a bug on every product page, and one fix solves all of them.&lt;/p&gt;

&lt;p&gt;Pick one representative URL per template, then save a Lighthouse report for each so you can diff the numbers later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx lighthouse https://example.com/products/sample-item &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;json &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./audit/baseline-product.json &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--chrome-flags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"--headless"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run each template through your baseline tool as well and note the scores in a spreadsheet or the audit ticket. Ten minutes here saves a lot of arguing later about whether a change helped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 1: Crawlability and Indexation
&lt;/h2&gt;

&lt;p&gt;This is the most important phase. If search engines can't crawl or index a page, nothing else on this list matters for that page.&lt;/p&gt;

&lt;h3&gt;
  
  
  robots.txt
&lt;/h3&gt;

&lt;p&gt;Check that robots.txt isn't blocking anything important. The two classic mistakes are a &lt;code&gt;Disallow: /&lt;/code&gt; copied over from staging, and rules that block CSS or JS directories. Google needs those files to render the page properly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://example.com/robots.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read every &lt;code&gt;Disallow&lt;/code&gt; line and ask whether it should really be there. Also remember that robots.txt controls crawling, not indexing. A blocked URL can still appear in results if other sites link to it, so it's the wrong tool for keeping a page out of Google. &lt;a href="https://developers.google.com/search/docs/crawling-indexing/robots/intro" rel="noopener noreferrer"&gt;Google's robots.txt documentation&lt;/a&gt; covers the syntax and edge cases well.&lt;/p&gt;

&lt;h3&gt;
  
  
  XML sitemap
&lt;/h3&gt;

&lt;p&gt;Your sitemap should list only canonical, indexable URLs that return a 200. No redirects, no 404s, no noindexed pages. Reference it in robots.txt with a &lt;code&gt;Sitemap:&lt;/code&gt; line and submit it in Search Console.&lt;/p&gt;

&lt;p&gt;Here's a quick way to spot bad entries in a simple, single-file sitemap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://example.com/sitemap.xml &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-oP&lt;/span&gt; &lt;span class="s1"&gt;'(?&amp;lt;=&amp;lt;loc&amp;gt;)[^&amp;lt;]+'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; url&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
      &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s1"&gt;'%{http_code}'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;done&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s1"&gt;'^200'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anything this prints needs to be fixed or removed from the sitemap. One more note: Google ignores &lt;code&gt;priority&lt;/code&gt; and &lt;code&gt;changefreq&lt;/code&gt;, but it does use &lt;code&gt;lastmod&lt;/code&gt; when the value is accurate. If your CMS sets &lt;code&gt;lastmod&lt;/code&gt; to today's date on every build, fix that too.&lt;/p&gt;

&lt;h3&gt;
  
  
  noindex in meta tags and headers
&lt;/h3&gt;

&lt;p&gt;There are two ways to tell search engines not to index a page, and you need to check both:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# HTTP header&lt;/span&gt;
curl &lt;span class="nt"&gt;-sI&lt;/span&gt; https://example.com/some-page | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; x-robots-tag

&lt;span class="c"&gt;# Meta tag in the HTML&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://example.com/some-page | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'name="robots"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The header version is the sneaky one. It's often set at the server or CDN level for staging environments and then accidentally carried into production. It won't show up when you inspect the page source, so marketers almost never catch it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Canonical tags
&lt;/h3&gt;

&lt;p&gt;Every indexable page should have a self-referencing canonical tag with an absolute URL. Rules worth checking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exactly one canonical per page.&lt;/li&gt;
&lt;li&gt;It points to a URL that returns a 200, not a redirect or a 404.&lt;/li&gt;
&lt;li&gt;Paginated pages and filtered listing pages don't all point to page one unless that's really what you want.&lt;/li&gt;
&lt;li&gt;The canonical in the HTML matches any canonical sent in an HTTP &lt;code&gt;Link&lt;/code&gt; header.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember that a canonical is a hint, not a directive. If your canonicals contradict your internal links and sitemap, Google may pick its own.&lt;/p&gt;

&lt;h3&gt;
  
  
  Status codes and redirect chains
&lt;/h3&gt;

&lt;p&gt;Pages that don't exist should return a real 404 (or 410), not a 200 with "Page not found" in the body. Google calls those soft 404s, and they waste crawl effort. Test it directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s1"&gt;'%{http_code}\n'&lt;/span&gt; https://example.com/this-page-does-not-exist-123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, check redirects. Permanent moves should use a 301 (or 308), and each redirect should take one hop to reach its final URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sIL&lt;/span&gt; http://example.com/old-page | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-iE&lt;/span&gt; &lt;span class="s1"&gt;'^(HTTP|location)'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see &lt;code&gt;http&lt;/code&gt; to &lt;code&gt;https&lt;/code&gt; to &lt;code&gt;www&lt;/code&gt; to a trailing-slash version, that's a three-hop chain. Collapse it into a single redirect straight to the final URL. Chains build up quietly after every migration, so run this on old URLs that still get backlinks.&lt;/p&gt;

&lt;h3&gt;
  
  
  JavaScript rendering
&lt;/h3&gt;

&lt;p&gt;If your site is a single-page app, this check matters more than any other. Compare what the server sends with what the browser renders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://example.com/products/sample-item | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"sample item name"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your main content and internal links aren't in the server response, search engines have to execute your JavaScript to see them. Google can render JS, but rendering can be delayed, and other crawlers often won't do it at all. Use the URL Inspection tool in Search Console to view the rendered HTML Google actually captured.&lt;/p&gt;

&lt;p&gt;For content-heavy pages, server-side rendering or static generation is the safest choice. Also make sure navigation uses real &lt;code&gt;&amp;lt;a href&amp;gt;&lt;/code&gt; links. Click handlers on &lt;code&gt;div&lt;/code&gt;s don't count as links to a crawler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 2: Site Architecture and Internal Linking
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Click depth
&lt;/h3&gt;

&lt;p&gt;Important pages should be reachable within three clicks of the homepage. Your crawler will report click depth for every URL. If key product or service pages sit five or six levels deep behind pagination, add links from category pages, navigation or related-content blocks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Orphan pages
&lt;/h3&gt;

&lt;p&gt;An orphan page is one with no internal links pointing to it. It might be in your sitemap, but if nothing on the site links to it, Google treats it as unimportant. To find orphans, export the URLs from your crawl and compare them with the URLs in your sitemap. Anything in the sitemap that the crawler never reached needs a link from somewhere relevant.&lt;/p&gt;

&lt;h3&gt;
  
  
  URL structure
&lt;/h3&gt;

&lt;p&gt;Keep URLs lowercase, use hyphens between words, and leave session IDs and tracking parameters out of internal links. Pick one trailing-slash convention and enforce it with a redirect. &lt;code&gt;/blog/post&lt;/code&gt; and &lt;code&gt;/blog/post/&lt;/code&gt; are two different URLs as far as a crawler is concerned.&lt;/p&gt;

&lt;h3&gt;
  
  
  Breadcrumbs and a custom 404
&lt;/h3&gt;

&lt;p&gt;Breadcrumbs give users a way back up the hierarchy and give search engines a clear map of your structure, especially when paired with &lt;code&gt;BreadcrumbList&lt;/code&gt; markup. Your custom 404 page should help people find their way (search box, popular links) while still returning a 404 status code. Check the status code with the &lt;code&gt;curl&lt;/code&gt; command from Phase 1.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 3: Performance and Core Web Vitals
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Know the thresholds
&lt;/h3&gt;

&lt;p&gt;Google measures page experience with three Core Web Vitals, assessed at the 75th percentile of real visits:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;What it measures&lt;/th&gt;
&lt;th&gt;Good&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Largest Contentful Paint (LCP)&lt;/td&gt;
&lt;td&gt;How fast the main content appears&lt;/td&gt;
&lt;td&gt;2.5 s or less&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interaction to Next Paint (INP)&lt;/td&gt;
&lt;td&gt;How quickly the page responds to input&lt;/td&gt;
&lt;td&gt;200 ms or less&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cumulative Layout Shift (CLS)&lt;/td&gt;
&lt;td&gt;How much the layout jumps while loading&lt;/td&gt;
&lt;td&gt;0.1 or less&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;a href="https://web.dev/articles/vitals" rel="noopener noreferrer"&gt;Core Web Vitals thresholds on web.dev&lt;/a&gt; explain how each one is measured if you want the details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lab data vs field data
&lt;/h3&gt;

&lt;p&gt;Lighthouse gives you &lt;strong&gt;lab data&lt;/strong&gt;: a single simulated load on a throttled device. It's great for debugging because it's repeatable. But Google uses &lt;strong&gt;field data&lt;/strong&gt; from real Chrome users (the CrUX dataset), which you'll find at the top of PageSpeed Insights and in the Core Web Vitals report in Search Console.&lt;/p&gt;

&lt;p&gt;So don't panic over one bad Lighthouse run, and don't celebrate one good one either. Use the field data to decide what to fix and lab data to work out how.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix LCP
&lt;/h3&gt;

&lt;p&gt;The LCP element is usually a hero image or a large heading. Common fixes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don't lazy-load the LCP image. &lt;code&gt;loading="lazy"&lt;/code&gt; above the fold is one of the most common LCP bugs I see.&lt;/li&gt;
&lt;li&gt;Tell the browser it's important with &lt;code&gt;fetchpriority="high"&lt;/code&gt;, or preload it.&lt;/li&gt;
&lt;li&gt;Serve modern formats like WebP or AVIF, at the size actually displayed.&lt;/li&gt;
&lt;li&gt;Cut server response time (TTFB) with caching, because nothing can paint before the HTML arrives.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/img/hero.avif"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Product dashboard overview"&lt;/span&gt;
     &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"1200"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"600"&lt;/span&gt; &lt;span class="na"&gt;fetchpriority=&lt;/span&gt;&lt;span class="s"&gt;"high"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Fix INP
&lt;/h3&gt;

&lt;p&gt;INP is usually a JavaScript problem. Break up long tasks so the main thread can respond to input, defer non-critical scripts, and take a hard look at third-party tags. Chat widgets, A/B testing tools and stacked analytics scripts are frequent offenders. The Performance panel in DevTools will show you exactly which tasks block interactions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix CLS
&lt;/h3&gt;

&lt;p&gt;Always set &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; (or &lt;code&gt;aspect-ratio&lt;/code&gt;) on images and video so the browser reserves space before they load. Reserve space for ads, embeds and cookie banners. If web fonts cause text to reflow, look at &lt;code&gt;font-display&lt;/code&gt; and preloading your main font file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Delivery basics
&lt;/h3&gt;

&lt;p&gt;These are quick server-side wins, and you can verify all of them from the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Compression (look for br or gzip)&lt;/span&gt;
curl &lt;span class="nt"&gt;-sI&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Accept-Encoding: br,gzip'&lt;/span&gt; https://example.com | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; content-encoding

&lt;span class="c"&gt;# Caching on static assets&lt;/span&gt;
curl &lt;span class="nt"&gt;-sI&lt;/span&gt; https://example.com/assets/app.js | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; cache-control

&lt;span class="c"&gt;# HTTP/2 support&lt;/span&gt;
curl &lt;span class="nt"&gt;-sI&lt;/span&gt; &lt;span class="nt"&gt;--http2&lt;/span&gt; https://example.com | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Static assets with hashed filenames can use long cache lifetimes. Add a CDN if your users are spread out geographically, and make sure CSS and JS are minified in production builds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 4: On-Page Technical Elements
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Title tags and meta descriptions per template
&lt;/h3&gt;

&lt;p&gt;Check that every template generates a unique, descriptive title and meta description from real page data. The common bugs are duplicates on paginated pages, filtered URLs that all inherit the category title, and empty fallbacks when a field is missing in the CMS. Keep titles to roughly 60 characters so they don't get cut off in results. A &lt;a href="https://seositechecker.pro/meta-tag-analyzer" rel="noopener noreferrer"&gt;meta tag analyzer&lt;/a&gt; will show you how a page's tags will look in search and flag length problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Heading hierarchy
&lt;/h3&gt;

&lt;p&gt;One H1 per page, describing the page's main topic. Use H2 and H3 for structure, not for styling. If a designer wants smaller bold text, that's a CSS class, not an &lt;code&gt;&amp;lt;h4&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  lang, viewport and charset
&lt;/h3&gt;

&lt;p&gt;These are tiny, and templates still get them wrong:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Image alt text
&lt;/h3&gt;

&lt;p&gt;Make &lt;code&gt;alt&lt;/code&gt; a required prop in your image component, so it can't be skipped. Describe what the image shows. Purely decorative images should use an empty &lt;code&gt;alt=""&lt;/code&gt; so screen readers skip them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Open Graph and Twitter cards
&lt;/h3&gt;

&lt;p&gt;These don't affect rankings directly, but they control how your links look when shared on social platforms and in chat apps. At minimum, set &lt;code&gt;og:title&lt;/code&gt;, &lt;code&gt;og:description&lt;/code&gt;, &lt;code&gt;og:image&lt;/code&gt; and &lt;code&gt;og:url&lt;/code&gt; per page.&lt;/p&gt;

&lt;h3&gt;
  
  
  hreflang, if you're multilingual
&lt;/h3&gt;

&lt;p&gt;If you serve the same content in multiple languages or regions, each version needs &lt;code&gt;hreflang&lt;/code&gt; tags pointing to every other version, including itself. The tags must be reciprocal. If page A points to page B, page B must point back to A, or Google ignores the pair.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 5: Security and Server Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  HTTPS everywhere, plus HSTS
&lt;/h3&gt;

&lt;p&gt;Every HTTP URL should 301 to its HTTPS equivalent. Once that's solid, add an HSTS header so browsers go straight to HTTPS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sI&lt;/span&gt; https://example.com | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; strict-transport-security
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Mixed content
&lt;/h3&gt;

&lt;p&gt;An HTTPS page that loads images, scripts or styles over HTTP triggers mixed-content warnings, and browsers may block those resources. Open the DevTools console on your main templates and look for warnings. Hardcoded &lt;code&gt;http://&lt;/code&gt; URLs in old CMS content are the usual culprit.&lt;/p&gt;

&lt;h3&gt;
  
  
  One canonical host
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;http://example.com&lt;/code&gt;, &lt;code&gt;http://www.example.com&lt;/code&gt;, &lt;code&gt;https://example.com&lt;/code&gt; and &lt;code&gt;https://www.example.com&lt;/code&gt; should all end up at the same URL with a single 301. Run the redirect check from Phase 1 against each variant. Duplicate hosts split your signals and waste crawl effort.&lt;/p&gt;

&lt;h3&gt;
  
  
  Leaky headers and directory listing
&lt;/h3&gt;

&lt;p&gt;Hide server version details in headers like &lt;code&gt;Server&lt;/code&gt; and &lt;code&gt;X-Powered-By&lt;/code&gt;, and turn off directory browsing. These are security issues first, but site audit tools flag them, and they're five-minute fixes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 6: Structured Data
&lt;/h2&gt;

&lt;p&gt;Structured data tells search engines what your content &lt;em&gt;is&lt;/em&gt;, not just what it says. For most sites, the useful types are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Organization&lt;/code&gt; (or &lt;code&gt;LocalBusiness&lt;/code&gt; for businesses with a physical location)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BreadcrumbList&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Article&lt;/code&gt; for blog posts&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Product&lt;/code&gt; for e-commerce&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use JSON-LD, and generate it from the same data that renders the visible content so the two never drift apart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"application/ld+json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@context&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://schema.org&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Organization&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Example Co&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com/logo.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Validate every template with the &lt;a href="https://search.google.com/test/rich-results" rel="noopener noreferrer"&gt;Rich Results Test&lt;/a&gt;. One expectation to set with your team: Google now shows FAQ rich results only for a small set of authoritative sites, such as government and health sites. FAQ markup is still valid, but don't promise anyone those dropdowns in search results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 7: Prioritize, Ship and Prevent Regressions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Turn findings into tickets
&lt;/h3&gt;

&lt;p&gt;An audit is only useful if it turns into shipped work. Score each finding on two axes, impact and effort, and work through them in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Indexing blockers.&lt;/strong&gt; Stray noindex, robots.txt blocks, broken canonicals, rendering failures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Template-level fixes.&lt;/strong&gt; One change, hundreds of pages fixed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance work&lt;/strong&gt; on the templates with the worst field data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Single-page fixes and minor warnings.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're wondering how to improve SEO score in a way that actually matters, this is it: fix the issues with the biggest blast radius first, not whichever warning is easiest to clear.&lt;/p&gt;

&lt;h3&gt;
  
  
  Catch regressions in CI
&lt;/h3&gt;

&lt;p&gt;The best audit is the one you never have to repeat by hand. Lighthouse CI can fail a build when performance or SEO scores drop below a budget:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ci"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"collect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:3000/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:3000/blog/sample-post"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"assert"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"assertions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"categories:seo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"minScore"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.95&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"categories:performance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"warn"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"minScore"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"cumulative-layout-shift"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"maxNumericValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"largest-contentful-paint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"warn"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"maxNumericValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2500&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save that as &lt;code&gt;lighthouserc.json&lt;/code&gt; and run &lt;code&gt;npx @lhci/cli autorun&lt;/code&gt; in your pipeline. I'd also add a post-deploy smoke test that fails loudly if production ever serves a noindex:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/"&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;curl &lt;span class="nt"&gt;-sI&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$URL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-qi&lt;/span&gt; &lt;span class="s1"&gt;'x-robots-tag:.*noindex'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="o"&gt;||&lt;/span&gt; curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$URL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-qiE&lt;/span&gt; &lt;span class="s1"&gt;'name="robots"[^&amp;gt;]*noindex'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"noindex found on production: &lt;/span&gt;&lt;span class="nv"&gt;$URL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's a few lines of shell, and it guards against one of the most expensive SEO bugs there is.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Copy-Paste Checklist
&lt;/h2&gt;

&lt;p&gt;Drop this into a GitHub issue or PR description and tick items off as you go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;### Phase 0: Baseline&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] One URL per template selected
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Lighthouse JSON and baseline scores saved

&lt;span class="gu"&gt;### Phase 1: Crawl and index&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] robots.txt blocks nothing important (CSS/JS included)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Sitemap lists only 200, canonical, indexable URLs
&lt;span class="p"&gt;-&lt;/span&gt; [ ] No stray noindex in meta tags or X-Robots-Tag headers
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Self-referencing absolute canonicals on indexable pages
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Real 404s, no soft 404s
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Redirects are single-hop 301s
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Main content and links present in server HTML

&lt;span class="gu"&gt;### Phase 2: Architecture&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Key pages within 3 clicks
&lt;span class="p"&gt;-&lt;/span&gt; [ ] No orphan pages
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Consistent, lowercase, hyphenated URLs

&lt;span class="gu"&gt;### Phase 3: Performance&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] LCP, INP and CLS pass in field data
&lt;span class="p"&gt;-&lt;/span&gt; [ ] LCP image not lazy-loaded
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Compression, caching and HTTP/2 enabled

&lt;span class="gu"&gt;### Phase 4: On-page&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Unique titles and descriptions per template
&lt;span class="p"&gt;-&lt;/span&gt; [ ] One H1, logical heading order
&lt;span class="p"&gt;-&lt;/span&gt; [ ] lang, charset and viewport set
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Alt text required in image component

&lt;span class="gu"&gt;### Phase 5: Security&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] HTTPS with HSTS, no mixed content
&lt;span class="p"&gt;-&lt;/span&gt; [ ] One canonical host

&lt;span class="gu"&gt;### Phase 6: Structured data&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] JSON-LD validates in Rich Results Test

&lt;span class="gu"&gt;### Phase 7: Prevent regressions&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Lighthouse CI budgets in pipeline
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Post-deploy noindex check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a check fails and you're not sure why it matters or how to fix it, this &lt;a href="https://seositechecker.pro/seo-checks" rel="noopener noreferrer"&gt;full reference of 70 SEO checks, explained&lt;/a&gt; covers each one in plain terms, with a fix for each failing result.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What should an SEO audit checklist include?
&lt;/h3&gt;

&lt;p&gt;At minimum: crawlability and indexation (robots.txt, sitemaps, noindex, canonicals, status codes), site architecture, Core Web Vitals and performance, on-page elements like titles and headings, HTTPS and server configuration, and structured data. A complete marketing audit also covers content quality and backlinks.&lt;/p&gt;

&lt;h3&gt;
  
  
  How often should you run a technical SEO audit?
&lt;/h3&gt;

&lt;p&gt;Do a full audit once or twice a year, plus a targeted one after any major release, redesign, framework change or migration. Between audits, automated checks in CI and a weekly look at Search Console's Pages and Core Web Vitals reports will catch most regressions early.&lt;/p&gt;

&lt;h3&gt;
  
  
  How long does an SEO audit take?
&lt;/h3&gt;

&lt;p&gt;For a small site with a few templates, a developer can work through this checklist in half a day to a day. Large sites with many templates, multiple languages or JavaScript rendering issues can take a week or more, mostly because of investigation time rather than the checks themselves.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I do an SEO audit myself for free?
&lt;/h3&gt;

&lt;p&gt;Yes. Google Search Console, Lighthouse, PageSpeed Insights, the Rich Results Test, the free version of Screaming Frog and &lt;code&gt;curl&lt;/code&gt; cover everything in this checklist. Paid tools mainly add scale, scheduling and backlink data, which you won't need for a developer-focused technical audit.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's the difference between a technical SEO audit and an on-page audit?
&lt;/h3&gt;

&lt;p&gt;A technical audit checks whether search engines can crawl, render, index and load your pages efficiently. An on-page audit checks whether each page's content and markup clearly match what people search for. Developers usually own the technical side, and content teams own most of the on-page side.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does passing every check mean my site will rank?
&lt;/h3&gt;

&lt;p&gt;No. Passing every check removes the obstacles, but rankings still depend on content that matches search intent and on links from trusted sites. Think of a clean technical audit as a requirement for ranking, not a guarantee of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Audit templates instead of pages, fix indexing blockers before anything else, and put the important checks into CI so the same bug never ships twice. Do that, and SEO stops being a scary PDF from marketing and becomes just another part of your test suite.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>performance</category>
    </item>
    <item>
      <title>Why UK Students Rely on Professional Coursework Writing Services in 2026</title>
      <dc:creator>Jay Barker</dc:creator>
      <pubDate>Fri, 20 Feb 2026 20:04:47 +0000</pubDate>
      <link>https://dev.to/jaybarker/why-uk-students-rely-on-professional-coursework-writing-services-in-2026-9km</link>
      <guid>https://dev.to/jaybarker/why-uk-students-rely-on-professional-coursework-writing-services-in-2026-9km</guid>
      <description>&lt;h2&gt;
  
  
  Introduction: The Academic Pressure Facing UK Students in 2026
&lt;/h2&gt;

&lt;p&gt;University life in 2026 looks very different from what it did even five years ago. The academic bar is higher, competition is tougher and expectations are relentless. For many UK students, coursework now carries more weight than traditional exams. Instead of one final test deciding everything, grades are built through essays, reports, case studies, research papers and practical assignments spread across the entire academic year.&lt;/p&gt;

&lt;p&gt;On paper, that sounds fair. In reality, it means constant deadlines.&lt;/p&gt;

&lt;p&gt;At the same time, students are juggling part-time jobs, internships, placements, and in many cases, rising living costs. International students are adapting to a new academic culture. Domestic students are navigating increasingly technical subject requirements. Mental health conversations are more open than ever, yet the pressure has not reduced.&lt;/p&gt;

&lt;p&gt;That’s why many students are turning to &lt;a href="https://britishcontentwriters.co.uk/coursework-writing/" rel="noopener noreferrer"&gt;professional coursework writing services&lt;/a&gt; not as shortcuts, but as structured academic support systems. The demand for reliable coursework writing help has grown significantly, particularly among students aiming for high classifications or balancing multiple commitments.&lt;/p&gt;

&lt;p&gt;In 2026, coursework support is less about desperation and more about strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Coursework Writing? (And Why It Matters More Than Ever)
&lt;/h2&gt;

&lt;p&gt;Before understanding why students rely on external help, it’s important to clarify what coursework actually involves.&lt;/p&gt;

&lt;h3&gt;
  
  
  Definition of Coursework in UK Universities
&lt;/h3&gt;

&lt;p&gt;In the UK academic system, coursework refers to assessed academic tasks completed during a module rather than in a single final examination. These assignments are designed to evaluate understanding, research skills, critical thinking and subject mastery over time.&lt;/p&gt;

&lt;p&gt;Coursework can include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Analytical essays&lt;/li&gt;
&lt;li&gt;Case studies&lt;/li&gt;
&lt;li&gt;Business reports&lt;/li&gt;
&lt;li&gt;Lab reports&lt;/li&gt;
&lt;li&gt;Literature reviews&lt;/li&gt;
&lt;li&gt;Reflective journals&lt;/li&gt;
&lt;li&gt;Research papers&lt;/li&gt;
&lt;li&gt;Presentations&lt;/li&gt;
&lt;li&gt;Poster submissions&lt;/li&gt;
&lt;li&gt;Project-based assignments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unlike exams, coursework demands sustained research, referencing accuracy, structured arguments, and academic writing precision. It’s not just about knowing the material, it’s about presenting it professionally.&lt;/p&gt;

&lt;p&gt;This is where many students struggle.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Coursework Impacts Final Grades
&lt;/h3&gt;

&lt;p&gt;In many UK universities, coursework can account for 50% to 100% of a module’s final mark. Some postgraduate programmes are entirely coursework-based.&lt;/p&gt;

&lt;p&gt;That means one poorly structured report or weakly argued essay can significantly impact a student’s degree classification.&lt;/p&gt;

&lt;p&gt;With classifications such as First-Class Honours and Distinction influencing postgraduate opportunities and career prospects, coursework performance carries long-term consequences.&lt;/p&gt;

&lt;h3&gt;
  
  
  Differences Between Coursework and Exams
&lt;/h3&gt;

&lt;p&gt;Exams test memory and time management under pressure.&lt;/p&gt;

&lt;p&gt;Coursework tests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Research depth&lt;/li&gt;
&lt;li&gt;Critical evaluation&lt;/li&gt;
&lt;li&gt;Referencing accuracy&lt;/li&gt;
&lt;li&gt;Academic tone&lt;/li&gt;
&lt;li&gt;Argument development&lt;/li&gt;
&lt;li&gt;Analytical reasoning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Students who excel in exams may not necessarily excel in structured academic writing. This is precisely why demand for coursework writing services continues to grow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4kqnusbo00daybg77u75.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4kqnusbo00daybg77u75.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Academic Pressure Has Increased in 2026
&lt;/h2&gt;

&lt;p&gt;Academic stress isn’t new but in 2026, several factors have intensified it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Competitive Job Market
&lt;/h3&gt;

&lt;p&gt;Employers increasingly look beyond degrees. They assess:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Academic performance&lt;/li&gt;
&lt;li&gt;Research exposure&lt;/li&gt;
&lt;li&gt;Practical assignments&lt;/li&gt;
&lt;li&gt;Portfolio quality&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A 2:1 is no longer “safe” in many competitive sectors. Students aiming for finance, law, healthcare, engineering or postgraduate research know they must maintain high coursework scores consistently.&lt;/p&gt;

&lt;p&gt;Coursework is no longer just a task, it’s part of a professional profile.&lt;/p&gt;

&lt;h3&gt;
  
  
  Work-Study Balance Challenges
&lt;/h3&gt;

&lt;p&gt;Many UK students now work part-time to support living expenses. Balancing employment with research-heavy assignments is demanding. Writing a 3,000-word analytical report after a shift is not easy.&lt;/p&gt;

&lt;p&gt;Deadlines do not pause for exhaustion.&lt;/p&gt;

&lt;p&gt;This time pressure often leads students to seek structured help, especially for complex or technical assignments.&lt;/p&gt;

&lt;h3&gt;
  
  
  International Student Adjustment Issues
&lt;/h3&gt;

&lt;p&gt;International students face additional hurdles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Academic language barriers&lt;/li&gt;
&lt;li&gt;Different referencing systems&lt;/li&gt;
&lt;li&gt;Cultural differences in argument structure&lt;/li&gt;
&lt;li&gt;Adapting to UK marking rubrics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even strong English speakers can struggle with UK academic tone. British academic writing requires clarity, critical balance and cautious argumentation, not overly assertive claims.&lt;/p&gt;

&lt;p&gt;Accessing professional guidance helps bridge that gap.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Detection &amp;amp; Academic Integrity Concerns
&lt;/h3&gt;

&lt;p&gt;Ironically, while AI tools are widely available, universities have tightened detection systems. Students using generic AI-generated text risk penalties due to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generic phrasing&lt;/li&gt;
&lt;li&gt;Lack of referencing depth&lt;/li&gt;
&lt;li&gt;Structural inconsistencies&lt;/li&gt;
&lt;li&gt;Detectable writing patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because of this, students increasingly prefer structured human academic support rather than relying solely on automated tools.&lt;/p&gt;

&lt;p&gt;The emphasis has shifted from “quick generation” to “credible academic quality”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcf1dwxbvnmavtbon0c3f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcf1dwxbvnmavtbon0c3f.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Professional Coursework Writing Services Actually Offer
&lt;/h2&gt;

&lt;p&gt;There’s a common misconception that coursework services simply “write essays for students”. In reality, reputable services offer a broader academic support system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom Written Assignments
&lt;/h3&gt;

&lt;p&gt;Professional coursework writers typically produce tailored content based on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Specific university guidelines&lt;/li&gt;
&lt;li&gt;Marking rubrics&lt;/li&gt;
&lt;li&gt;Module requirements&lt;/li&gt;
&lt;li&gt;Referencing style instructions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Assignments are structured to reflect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clear thesis statements&lt;/li&gt;
&lt;li&gt;Logical argument flow&lt;/li&gt;
&lt;li&gt;Evidence-based analysis&lt;/li&gt;
&lt;li&gt;Proper citations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For students seeking structured assistance, platforms offering dedicated coursework writing services provide clarity and consistency in academic formatting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Subject-Specific Experts
&lt;/h3&gt;

&lt;p&gt;High-quality services match students with subject specialists, whether in law, nursing, business, engineering or social sciences.&lt;/p&gt;

&lt;p&gt;This matters because coursework isn’t just about writing skill; it’s about subject expertise.&lt;/p&gt;

&lt;p&gt;A nursing reflective assignment differs significantly from a finance case study. Subject familiarity improves analytical depth and credibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  UK Referencing Styles (Harvard, APA, MLA, OSCOLA)
&lt;/h3&gt;

&lt;p&gt;Referencing errors are one of the most common reasons students lose marks.&lt;/p&gt;

&lt;p&gt;Professional writers are trained in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Harvard referencing&lt;/li&gt;
&lt;li&gt;APA style&lt;/li&gt;
&lt;li&gt;MLA formatting&lt;/li&gt;
&lt;li&gt;OSCOLA (especially for law students)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Correct citation structure enhances academic integrity and protects against plagiarism accusations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plagiarism-Free Guarantees
&lt;/h3&gt;

&lt;p&gt;Originality is non-negotiable in UK universities.&lt;/p&gt;

&lt;p&gt;Reliable services use advanced plagiarism detection systems and produce custom-written work rather than recycled templates. This reduces the risk associated with duplicated content.&lt;/p&gt;

&lt;p&gt;Students seeking professional support often prioritise plagiarism-free coursework above all else.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.turnitin.com/" rel="noopener noreferrer"&gt;Turnitin plagiarism detection system&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Editing &amp;amp; Proofreading Support
&lt;/h3&gt;

&lt;p&gt;Not every student needs full writing support. Many simply require:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Structural editing&lt;/li&gt;
&lt;li&gt;Argument refinement&lt;/li&gt;
&lt;li&gt;Grammar correction&lt;/li&gt;
&lt;li&gt;Referencing checks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This hybrid support model is becoming increasingly popular in 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  Top Reasons UK Students Choose Coursework Writing Help
&lt;/h2&gt;

&lt;p&gt;Students don’t seek help without reason. The motivations are often practical rather than irresponsible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tight Deadlines
&lt;/h3&gt;

&lt;p&gt;Multiple modules often mean overlapping submission dates. When three assignments fall within the same week, quality inevitably suffers.&lt;/p&gt;

&lt;p&gt;Professional support allows students to manage time more effectively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Complex Topics
&lt;/h3&gt;

&lt;p&gt;Advanced modules often introduce specialised topics requiring deep research. Without subject familiarity, students can spend excessive time understanding the basics before even beginning to write.&lt;/p&gt;

&lt;p&gt;Hiring a coursework writer with subject expertise can streamline that process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Language Barriers
&lt;/h3&gt;

&lt;p&gt;Even fluent non-native English speakers can struggle with academic nuance. UK academic tone emphasises critical evaluation, cautious phrasing, and evidence-led conclusions.&lt;/p&gt;

&lt;p&gt;Professional guidance helps refine clarity and coherence.&lt;/p&gt;

&lt;h3&gt;
  
  
  Desire for Higher Grades
&lt;/h3&gt;

&lt;p&gt;Some students performing at a 2:1 level aim for a First. Others want to secure Distinction in postgraduate study.&lt;/p&gt;

&lt;p&gt;External academic guidance often acts as a quality benchmark.&lt;/p&gt;

&lt;p&gt;For those considering structured academic support, many explore platforms where they can &lt;a href="https://britishcontentwriters.co.uk/hire-coursework-writer-uk/" rel="noopener noreferrer"&gt;hire a coursework writer in the UK&lt;/a&gt; who understands local marking criteria.&lt;/p&gt;

&lt;h3&gt;
  
  
  Confidential Academic Support
&lt;/h3&gt;

&lt;p&gt;Confidentiality remains a major concern. Reputable services maintain strict privacy policies and secure data handling practices.&lt;/p&gt;

&lt;p&gt;Students want reassurance that their information remains protected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Time Management &amp;amp; Mental Health
&lt;/h3&gt;

&lt;p&gt;Perhaps the most overlooked reason is wellbeing.&lt;/p&gt;

&lt;p&gt;Constant deadlines, financial pressure, and academic expectations can lead to burnout. Seeking academic support can reduce stress and allow students to focus on learning rather than panic-driven writing.&lt;/p&gt;

&lt;p&gt;In 2026, asking for help is no longer seen as weakness, it’s often a smart academic strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Are Coursework Writing Services Legal in the UK?
&lt;/h2&gt;

&lt;p&gt;One of the most common concerns students have is legality.&lt;/p&gt;

&lt;p&gt;The short answer? Coursework writing services themselves are not illegal in the UK. These platforms operate as academic support providers. They offer model answers, research assistance, editing, and structured guidance.&lt;/p&gt;

&lt;p&gt;The issue arises not from the service itself, but from how the material is used.&lt;/p&gt;

&lt;p&gt;Universities prohibit submitting purchased work as one’s own without modification or learning engagement. However, using model papers for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Research guidance&lt;/li&gt;
&lt;li&gt;Structural reference&lt;/li&gt;
&lt;li&gt;Formatting examples&lt;/li&gt;
&lt;li&gt;Understanding argument development&lt;/li&gt;
&lt;li&gt;Learning citation techniques&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;is comparable to using study guides or tutoring support.&lt;/p&gt;

&lt;p&gt;In 2026, responsible academic support is framed as collaborative learning rather than replacement learning. Many students use coursework assistance to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Improve drafts&lt;/li&gt;
&lt;li&gt;Understand complex topics&lt;/li&gt;
&lt;li&gt;Review referencing styles&lt;/li&gt;
&lt;li&gt;Refine structure before submission&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key difference lies in intent.&lt;/p&gt;

&lt;p&gt;When used ethically, coursework writing support becomes a study resource not a shortcut.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsanb96ad0cxkedkwoqvx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsanb96ad0cxkedkwoqvx.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Choose a Reliable Coursework Writing Service in 2026
&lt;/h2&gt;

&lt;p&gt;Not all academic support platforms offer the same quality. Students who decide to seek help must evaluate providers carefully.&lt;/p&gt;

&lt;p&gt;Here’s what separates professional services from risky ones.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check Writer Qualifications
&lt;/h3&gt;

&lt;p&gt;Credible services work with subject-specific experts, often holding postgraduate degrees in their field. A law assignment requires familiarity with case analysis. A nursing paper demands understanding of reflective models and clinical frameworks.&lt;/p&gt;

&lt;p&gt;Generic writers rarely deliver high distinctions.&lt;/p&gt;

&lt;p&gt;Students looking for comprehensive support often start with a detailed coursework writing guide for UK students to understand what quality standards should look like before selecting a provider.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plagiarism Reports
&lt;/h3&gt;

&lt;p&gt;Originality matters more than ever. Universities use advanced detection systems. A reliable service should provide plagiarism checks and custom-written content.&lt;/p&gt;

&lt;p&gt;Transparency is non-negotiable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Transparent Pricing
&lt;/h3&gt;

&lt;p&gt;Hidden fees are red flags. Clear pricing based on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deadline&lt;/li&gt;
&lt;li&gt;Word count&lt;/li&gt;
&lt;li&gt;Academic level&lt;/li&gt;
&lt;li&gt;Subject complexity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;indicates professionalism.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real Reviews &amp;amp; Reputation
&lt;/h3&gt;

&lt;p&gt;Independent reviews, testimonials, and online presence matter. Established academic platforms typically maintain long-term digital credibility rather than short-lived operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Privacy &amp;amp; GDPR Compliance
&lt;/h3&gt;

&lt;p&gt;UK-based services must comply with GDPR standards. Confidentiality policies should be clearly stated.&lt;/p&gt;

&lt;p&gt;Students should never feel uncertain about how their personal information is handled.&lt;/p&gt;

&lt;h3&gt;
  
  
  Revision Policies
&lt;/h3&gt;

&lt;p&gt;Even strong academic work may require minor refinements. A reliable provider offers structured revision options to ensure alignment with university feedback.&lt;/p&gt;

&lt;p&gt;For students ready to move forward confidently, structured platforms where they can &lt;a href="https://britishcontentwriters.co.uk/order-now/" rel="noopener noreferrer"&gt;order coursework online&lt;/a&gt; provide a clearer process than informal arrangements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of Hiring a UK-Based Coursework Writer
&lt;/h2&gt;

&lt;p&gt;Global writing services exist, but many UK students prefer working with UK-based academic writers. The reasons are practical.&lt;/p&gt;

&lt;h3&gt;
  
  
  Native Academic Tone
&lt;/h3&gt;

&lt;p&gt;British academic writing style differs from American or international conventions. UK marking often prioritises:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Balanced argumentation&lt;/li&gt;
&lt;li&gt;Critical evaluation&lt;/li&gt;
&lt;li&gt;Structured reasoning&lt;/li&gt;
&lt;li&gt;Cautious phrasing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A UK-based coursework writer naturally aligns with these expectations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding of UK Grading Criteria
&lt;/h3&gt;

&lt;p&gt;Degree classifications such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First-Class Honours&lt;/li&gt;
&lt;li&gt;Upper Second-Class (2:1)&lt;/li&gt;
&lt;li&gt;Lower Second-Class (2:2)&lt;/li&gt;
&lt;li&gt;Distinction (Postgraduate)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;require strategic writing depth.&lt;/p&gt;

&lt;p&gt;Writers familiar with UK marking rubrics understand how to structure arguments for higher classifications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cultural Familiarity
&lt;/h3&gt;

&lt;p&gt;Case studies often reference UK laws, healthcare frameworks, business environments, or public policy. A local writer understands contextual relevance.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OSCOLA referencing in law&lt;/li&gt;
&lt;li&gt;NHS policy references in nursing&lt;/li&gt;
&lt;li&gt;UK financial reporting standards in business&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This contextual awareness improves credibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Referencing Accuracy
&lt;/h3&gt;

&lt;p&gt;Harvard referencing remains widely used across UK institutions. Minor formatting errors can result in mark deductions.&lt;/p&gt;

&lt;p&gt;Students seeking expert-level formatting often choose to hire a coursework writer in the UK who is trained in local citation standards.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn6k3omt8azzzyht0pqk7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn6k3omt8azzzyht0pqk7.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Future of Coursework Writing Services (2026 and Beyond)
&lt;/h2&gt;

&lt;p&gt;The landscape of academic support is evolving rapidly.&lt;/p&gt;

&lt;p&gt;In 2026, coursework services are integrating:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI-assisted research tools (for efficiency)&lt;/li&gt;
&lt;li&gt;Human editing layers (for academic tone)&lt;/li&gt;
&lt;li&gt;Personalised mentoring feedback&lt;/li&gt;
&lt;li&gt;Structured research summaries&lt;/li&gt;
&lt;li&gt;Enhanced originality scanning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rather than replacing human expertise, AI is being used as a supplementary research accelerator.&lt;/p&gt;

&lt;p&gt;Students increasingly value:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Customisation&lt;/li&gt;
&lt;li&gt;Clarity&lt;/li&gt;
&lt;li&gt;Ethical academic guidance&lt;/li&gt;
&lt;li&gt;Structured writing frameworks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The future isn’t about automated content generation. It’s about hybrid academic collaboration where students remain engaged in learning while receiving structured assistance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions (FAQs)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is coursework writing?&lt;/strong&gt;&lt;br&gt;
Coursework writing refers to structured academic assignments completed during a university module rather than in a final exam. These include essays, reports, case studies, research papers, and reflective assignments that contribute significantly to final grades.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it safe to use coursework writing services?&lt;/strong&gt;&lt;br&gt;
When choosing reputable providers with strong privacy policies and originality guarantees, academic support services can be used safely. The key is to use the material ethically, as a learning reference or structural guide.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much do coursework writers charge in the UK?&lt;/strong&gt;&lt;br&gt;
Pricing varies depending on academic level, deadline, subject complexity, and word count. Urgent postgraduate assignments typically cost more than standard undergraduate essays due to research depth requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can coursework writing services guarantee plagiarism-free work?&lt;/strong&gt;&lt;br&gt;
Reputable services provide custom-written assignments and often supply plagiarism reports. However, students should always review and personalise content before submission.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Are coursework writing services legal in the USA and UK?&lt;/strong&gt;&lt;br&gt;
Yes, academic support services operate legally. Universities regulate how assignments are submitted, but accessing study assistance itself is not illegal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How fast can I get coursework done?&lt;/strong&gt;&lt;br&gt;
Some services offer urgent deadlines within 24–48 hours. However, complex research assignments benefit from longer timelines to ensure quality and depth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will my professor know if I use a coursework service?&lt;/strong&gt;&lt;br&gt;
Detection depends on writing consistency and submission integrity. Students are encouraged to use coursework support responsibly, as academic guidance rather than direct substitution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Smart Academic Support in a Competitive Era
&lt;/h2&gt;

&lt;p&gt;University education in 2026 is intense, competitive, and demanding. Coursework carries significant weight, expectations are higher, and students face multiple external pressures.&lt;/p&gt;

&lt;p&gt;Seeking structured academic support is no longer viewed purely as a last resort. For many UK students, it has become a practical strategy to maintain balance, improve quality and manage complex deadlines responsibly.&lt;/p&gt;

&lt;p&gt;Professional coursework writing services, when used ethically, can provide clarity, structure, and subject expertise that enhance learning rather than replace it.&lt;/p&gt;

&lt;p&gt;In a world where academic performance influences career trajectories, smart support systems matter.&lt;/p&gt;

&lt;p&gt;And increasingly, UK students are choosing to work strategically not struggle silently.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>beginners</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How Website Structure Impacts SEO Rankings</title>
      <dc:creator>Jay Barker</dc:creator>
      <pubDate>Fri, 13 Feb 2026 18:55:53 +0000</pubDate>
      <link>https://dev.to/jaybarker/how-website-structure-impacts-seo-rankings-4k81</link>
      <guid>https://dev.to/jaybarker/how-website-structure-impacts-seo-rankings-4k81</guid>
      <description>&lt;p&gt;When businesses think about SEO, they usually focus on keywords and backlinks. But one of the most overlooked ranking factors is website structure.&lt;/p&gt;

&lt;p&gt;A poorly structured website makes it difficult for search engines to crawl, understand, and rank your content, even if the content itself is high quality.&lt;/p&gt;

&lt;p&gt;Here’s how to fix that.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is an SEO-Friendly Website Structure?
&lt;/h2&gt;

&lt;p&gt;An SEO-friendly website structure is a logical hierarchy that organizes your pages in a way that improves crawlability and user experience.&lt;/p&gt;

&lt;p&gt;A strong structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keeps important pages within three clicks&lt;/li&gt;
&lt;li&gt;Groups related content together&lt;/li&gt;
&lt;li&gt;Uses clean, descriptive URLs&lt;/li&gt;
&lt;li&gt;Implements strong internal linking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Search engines use your internal links and site architecture to determine page importance and topical relevance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flat vs Deep Architecture
&lt;/h2&gt;

&lt;p&gt;Flat architecture is preferred for SEO.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;Homepage → Category → Page&lt;/p&gt;

&lt;p&gt;Deep structures with excessive subfolders reduce crawl frequency and delay indexing.&lt;/p&gt;

&lt;p&gt;Keep depth minimal and distribute authority evenly through internal linking.&lt;/p&gt;

&lt;h2&gt;
  
  
  URL Structure Matters
&lt;/h2&gt;

&lt;p&gt;SEO-friendly URLs should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Be short and descriptive&lt;/li&gt;
&lt;li&gt;Contain primary keywords&lt;/li&gt;
&lt;li&gt;Use hyphens&lt;/li&gt;
&lt;li&gt;Avoid dynamic parameters&lt;/li&gt;
&lt;li&gt;Maintain HTTPS security&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clean URLs improve both rankings and user trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Internal Linking Strategy
&lt;/h2&gt;

&lt;p&gt;Internal linking is your authority distribution system.&lt;/p&gt;

&lt;p&gt;Best practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Link from high-authority pages to important commercial pages&lt;/li&gt;
&lt;li&gt;Use descriptive anchor text&lt;/li&gt;
&lt;li&gt;Avoid orphan pages&lt;/li&gt;
&lt;li&gt;Strengthen topical clusters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Strong internal linking improves ranking consistency across your website.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Setup Essentials
&lt;/h2&gt;

&lt;p&gt;Beyond structure, technical elements must support SEO:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;XML sitemap submission&lt;/li&gt;
&lt;li&gt;Proper robots.txt configuration&lt;/li&gt;
&lt;li&gt;Canonical tags&lt;/li&gt;
&lt;li&gt;Structured data markup&lt;/li&gt;
&lt;li&gt;Optimised hosting&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Hosting &amp;amp; Performance Impact
&lt;/h2&gt;

&lt;p&gt;Your hosting environment influences crawl efficiency and Core Web Vitals.&lt;/p&gt;

&lt;p&gt;Cloud hosting typically provides better uptime and faster response times compared to shared hosting.&lt;/p&gt;

&lt;p&gt;Slow servers reduce crawl frequency and affect indexing speed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://seositechecker.pro/post/seo-friendly-website-structure-guide" rel="noopener noreferrer"&gt;SEO-friendly website structure&lt;/a&gt; isn’t just technical, it’s strategic.&lt;/p&gt;

&lt;p&gt;If your hierarchy is clean, your internal linking is strong, and your hosting is reliable, search engines will crawl, index, and rank your content more efficiently.&lt;/p&gt;

&lt;p&gt;Structure first. Rankings follow.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Jay Barker</dc:creator>
      <pubDate>Fri, 07 Nov 2025 22:16:13 +0000</pubDate>
      <link>https://dev.to/jaybarker/-3hi2</link>
      <guid>https://dev.to/jaybarker/-3hi2</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/nexibloom" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F11662%2Fe1700e73-c8fc-4c8a-bd35-43ed31b8d584.jpg" alt="Nexi Bloom LLC" width="500" height="500"&gt;
      &lt;div class="ltag__link__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3523633%2F7f237e59-4af7-4f59-ae4f-26a525dc2e50.png" alt="" width="298" height="297"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/nexibloom/how-seasonal-seo-campaigns-boost-business-growth-during-halloween-2025-56p" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;How Seasonal SEO Campaigns Boost Business Growth During Halloween 2025&lt;/h2&gt;
      &lt;h3&gt;Nexi Bloom for Nexi Bloom LLC ・ Oct 17&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#productivity&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#performance&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#design&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#news&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>productivity</category>
      <category>performance</category>
      <category>design</category>
      <category>news</category>
    </item>
    <item>
      <title>How Developers Can Speed Up Websites with Free HTML, CSS, and JS Minifiers</title>
      <dc:creator>Jay Barker</dc:creator>
      <pubDate>Tue, 30 Sep 2025 04:37:28 +0000</pubDate>
      <link>https://dev.to/jaybarker/how-developers-can-speed-up-websites-with-free-html-css-and-js-minifiers-3ic5</link>
      <guid>https://dev.to/jaybarker/how-developers-can-speed-up-websites-with-free-html-css-and-js-minifiers-3ic5</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Website speed is one of the most important ranking factors for both search engines and users. Slow-loading pages not only frustrate visitors but also lower engagement, conversions, and SEO performance. One of the most effective yet often overlooked methods for boosting speed is code minification. The process of removing unnecessary characters, spaces, and comments from your code.&lt;/p&gt;

&lt;p&gt;When done properly, minification can significantly reduce file sizes of HTML, CSS, and JavaScript, leading to faster load times, better Core Web Vitals, and improved user experiences. Best of all, developers no longer need expensive tools or complicated setups to achieve this. With today’s free minifier tools, you can optimize your code instantly with just a copy-paste.&lt;/p&gt;

&lt;p&gt;In this guide, we’ll explore how developers can use an &lt;a href="https://seositechecker.pro/html-minifier" rel="noopener noreferrer"&gt;HTML minifier tool&lt;/a&gt;, &lt;a href="https://seositechecker.pro/css-minifier" rel="noopener noreferrer"&gt;CSS minifier free&lt;/a&gt; platforms, and &lt;a href="https://seositechecker.pro/js-minifier" rel="noopener noreferrer"&gt;JS minifier online&lt;/a&gt; solutions to accelerate websites. You’ll learn what minification is, why it matters, how to use it safely, and which tools are the best options for 2025.&lt;/p&gt;

&lt;p&gt;👉 Start by testing your files with the &lt;a href="https://seositechecker.pro/category/website-management-tools" rel="noopener noreferrer"&gt;Free Minifier Tools on SEO Site Checker&lt;/a&gt; to see how much faster your website can be.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. What Is Code Minification (HTML / CSS / JS)?
&lt;/h2&gt;

&lt;p&gt;Code minification is the process of stripping out all unnecessary elements from your code without affecting its functionality. For example, a JavaScript minifier removes spaces, line breaks, and comments, turning human-readable code into a compressed format that browsers can still execute perfectly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML Minification: Removes whitespace, inline comments, and redundant tags.&lt;/li&gt;
&lt;li&gt;CSS Minification: Shortens class names (where possible), removes unused selectors, compresses colors, and eliminates formatting spaces.&lt;/li&gt;
&lt;li&gt;JS Minification: Deletes line breaks, optimizes variables, and reduces payload.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Minification is often confused with compression or bundling, but they’re not the same. Compression (e.g., Gzip, Brotli) happens at the server level, while bundling groups multiple files into one. Minification, on the other hand, focuses solely on cleaning up the code itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Why Minify HTML, CSS &amp;amp; JavaScript?
&lt;/h2&gt;

&lt;p&gt;Minifying your front-end code brings several performance benefits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Improved Page Speed → Reducing file sizes means fewer kilobytes to transfer. Faster pages score better in Google PageSpeed Insights and Lighthouse.&lt;/li&gt;
&lt;li&gt;Better SEO Performance → Google considers Core Web Vitals (Largest Contentful Paint, Cumulative Layout Shift, First Input Delay). Minified assets load faster and improve these metrics.&lt;/li&gt;
&lt;li&gt;Reduced Bandwidth Costs → Smaller files save resources on both the client and server side, especially important for mobile users with limited data.&lt;/li&gt;
&lt;li&gt;Smoother User Experience → Users notice when sites load faster, improving engagement and reducing bounce rate.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Studies show that every extra second of load time can reduce conversions by up to 20%. That’s why modern developers integrate minification into their build workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. When &amp;amp; Where to Apply Minification
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;During Development/Build: Ideally, minification happens automatically during build processes with tools like webpack, gulp, or Grunt.&lt;/li&gt;
&lt;li&gt;Critical CSS vs. Full CSS: Sometimes only critical CSS is inlined, while the rest is loaded separately. Minify both for performance.&lt;/li&gt;
&lt;li&gt;Custom vs. Library Scripts: Always minify custom JavaScript. Third-party libraries like jQuery are already minified, but double-check.&lt;/li&gt;
&lt;li&gt;Source Maps: Developers should keep unminified versions for debugging, using source maps to map errors back to readable code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Free HTML Minifier Tools Online
&lt;/h2&gt;

&lt;p&gt;There are dozens of HTML minifier tools online. They strip whitespace, remove inline comments, and collapse code. Popular free options include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://seositechecker.pro/category/website-management-tools" rel="noopener noreferrer"&gt;SEO Site Checker HTML Minifier Tool&lt;/a&gt; → simple, fast, and unlimited.&lt;/li&gt;
&lt;li&gt;Minify Code → Lightweight, web-based tool.&lt;/li&gt;
&lt;li&gt;HTML Minifier (npm) → CLI for developers who prefer terminal use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When using online minifiers, always ensure your code doesn’t contain sensitive information, since you’ll paste it into third-party platforms.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Free CSS Minifier Tools
&lt;/h2&gt;

&lt;p&gt;CSS files often grow bulky with comments, spaces, and unused selectors. CSS minifier free tools solve this problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://seositechecker.pro/css-minifier" rel="noopener noreferrer"&gt;SEO Site Checker CSS Minifier&lt;/a&gt; → fast, safe, and browser-based.&lt;/li&gt;
&lt;li&gt;CSSNano → A popular npm package for build pipelines.&lt;/li&gt;
&lt;li&gt;CleanCSS → An online CSS compressor with multiple settings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most tools offer options to preserve comments or remove unused selectors. For production websites, stripping everything except what’s necessary is usually best.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Free JS Minifier Tools / Online Options
&lt;/h2&gt;

&lt;p&gt;JavaScript is often the heaviest asset on a site. JS minifier online tools help reduce payloads dramatically. Options include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://seositechecker.pro/js-minifier" rel="noopener noreferrer"&gt;SEO Site Checker JS Minifier&lt;/a&gt; → quick browser-based optimization.&lt;/li&gt;
&lt;li&gt;UglifyJS → Long-standing minification and obfuscation tool.&lt;/li&gt;
&lt;li&gt;Terser → ES6+ support, widely used in modern frameworks.&lt;/li&gt;
&lt;li&gt;Google Closure Compiler → Advanced optimization for large projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When minifying JS, ensure source maps are enabled to debug errors easily.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Best Practices &amp;amp; Pitfalls to Avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Always keep a non-minified backup.&lt;/li&gt;
&lt;li&gt;Use source maps for debugging.&lt;/li&gt;
&lt;li&gt;Minify during deployment, not manually each time.&lt;/li&gt;
&lt;li&gt;Be cautious with inline JavaScript or dynamic template engines, aggressive minification can break them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. Combining Minification with Other Optimizations
&lt;/h2&gt;

&lt;p&gt;Minification should be paired with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gzip/Brotli compression&lt;/li&gt;
&lt;li&gt;HTTP/2 multiplexing&lt;/li&gt;
&lt;li&gt;Caching &amp;amp; versioning&lt;/li&gt;
&lt;li&gt;Lazy loading for images and JS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together, these ensure maximum performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Measuring Impact &amp;amp; Monitoring
&lt;/h2&gt;

&lt;p&gt;Use tools like Google Lighthouse, PageSpeed Insights, or WebPageTest to benchmark performance. Compare load time, file size, and Core Web Vitals before and after minification.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q1: What is an HTML minifier tool?&lt;/strong&gt;&lt;br&gt;
An online or CLI tool that reduces HTML file size by removing unnecessary characters without affecting output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q2: Is a CSS minifier free tool safe to use?&lt;/strong&gt;&lt;br&gt;
Yes, as long as you use trusted platforms like SEO Site Checker’s CSS Minifier&lt;br&gt;
. For sensitive projects, use local/CLI versions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q3: How do I choose a JS minifier online?&lt;/strong&gt;&lt;br&gt;
Pick one that supports modern JavaScript (ES6+). &lt;a href="https://seositechecker.pro/css-minifier" rel="noopener noreferrer"&gt;SEO Site Checker’s JS Minifier&lt;/a&gt; is a reliable option for quick use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q4: Can minifying break my code?&lt;/strong&gt;&lt;br&gt;
Yes, especially if inline scripts or dynamic templates are aggressively stripped. Always test after minification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q5: Should I minify everything?&lt;/strong&gt;&lt;br&gt;
Yes, but exclude development files and keep a readable copy for debugging.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading (External Links)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kinsta.com/blog/minify-javascript/?utm_source=seositechecker.pro" rel="noopener noreferrer"&gt;How to Minify JavaScript – Kinsta&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.logrocket.com/complete-best-practices-minifying-css/?utm_source=seositechecker.pro" rel="noopener noreferrer"&gt;Best Practices for Minifying CSS – LogRocket&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wp-rocket.me/blog/best-free-css-and-javascript-minification-tools/?utm_source=seositechecker.pro" rel="noopener noreferrer"&gt;Best Free CSS &amp;amp; JS Minification Tools – WP Rocket&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Website performance is more important than ever. Minifying HTML, CSS, and JavaScript is a low-effort, high-impact way to improve speed, user experience, and SEO. The best part? You don’t need to pay for expensive solutions — with free tools like the &lt;a href="https://seositechecker.pro/html-minifier" rel="noopener noreferrer"&gt;HTML Minifier Tool&lt;/a&gt;, &lt;a href="https://seositechecker.pro/css-minifier" rel="noopener noreferrer"&gt;CSS Minifier Free&lt;/a&gt;, and &lt;a href="https://seositechecker.pro/js-minifier" rel="noopener noreferrer"&gt;JS Minifier Online&lt;/a&gt;, you can optimize code in minutes.&lt;/p&gt;

&lt;p&gt;👉 Try the &lt;a href="https://seositechecker.pro/category/website-management-tools" rel="noopener noreferrer"&gt;Free Minifier Tools on SEO Site Checker&lt;/a&gt; to get started today and see immediate improvements in your website performance.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Why Multi-Tenant Blogging Platforms Are the Future of Content Creation</title>
      <dc:creator>Jay Barker</dc:creator>
      <pubDate>Sun, 28 Sep 2025 22:46:17 +0000</pubDate>
      <link>https://dev.to/jaybarker/why-multi-tenant-blogging-platforms-are-the-future-of-content-creation-4mpc</link>
      <guid>https://dev.to/jaybarker/why-multi-tenant-blogging-platforms-are-the-future-of-content-creation-4mpc</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Blogging has come a long way since the early 2000s. Back then, setting up a blog meant choosing between static HTML pages, installing WordPress on a server, or using a hosted service like Blogger. Fast forward to 2025, and the blogging ecosystem looks completely different. Content creators, agencies, and businesses now demand platforms that are scalable, cost-effective, SEO-friendly, and flexible enough to manage multiple projects at once.&lt;/p&gt;

&lt;p&gt;That’s where multi-tenant blogging platforms come in. Unlike traditional CMS solutions that operate in isolation, a multi-tenant architecture allows multiple blogs (or even businesses) to run on a shared infrastructure while maintaining independence.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore why multi-tenant blogging platforms are reshaping the content industry, compare them to traditional solutions, and explain why platforms like &lt;a href="https://devdominion.com/" rel="noopener noreferrer"&gt;Dev Dominion&lt;/a&gt; are leading this change.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Multi-Tenant Blogging Platform?
&lt;/h2&gt;

&lt;p&gt;In software, multi-tenancy means a single software instance serves multiple users (tenants) while keeping their data and experiences separate. Think of it like an apartment building: everyone shares the structure, but each tenant has their own private unit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Applied to blogging:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Traditional CMS (single-tenant): Each site runs on its own installation, requiring separate hosting, updates, and security patches.&lt;/p&gt;

&lt;p&gt;Multi-tenant CMS: Multiple blogs or sites run on a single platform instance. Users benefit from shared resources (hosting, updates, security) while keeping their blogs independent.&lt;/p&gt;

&lt;p&gt;For developers and content creators, this architecture simplifies management, reduces costs, and improves scalability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-Tenant vs Traditional CMS
&lt;/h2&gt;

&lt;p&gt;When comparing traditional CMS platforms with multi-tenant blogging platforms, the differences are clear:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Setup
&lt;/h3&gt;

&lt;p&gt;Traditional CMS: Requires manual installs, plugins, and separate hosting for each site.&lt;/p&gt;

&lt;p&gt;Multi-tenant: Centralized setup with instant provisioning spin up a new blog in minutes.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Updates
&lt;/h3&gt;

&lt;p&gt;Traditional CMS: Each site must be updated individually (plugins, themes, security patches).&lt;/p&gt;

&lt;p&gt;Multi-tenant: One platform update applies to all blogs automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Cost
&lt;/h3&gt;

&lt;p&gt;Traditional CMS: Pay separately for hosting and maintenance for each site.&lt;/p&gt;

&lt;p&gt;Multi-tenant: Shared infrastructure significantly reduces overall costs.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Scalability
&lt;/h3&gt;

&lt;p&gt;Traditional CMS: Managing many sites (e.g., for clients) is time-consuming.&lt;/p&gt;

&lt;p&gt;Multi-tenant: Easily manage dozens or even hundreds of blogs in one environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Security
&lt;/h3&gt;

&lt;p&gt;Traditional CMS: Each site is responsible for its own patches and protection.&lt;/p&gt;

&lt;p&gt;Multi-tenant: Security is handled at the platform level, keeping all tenants safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Benefits of Multi-Tenant Blogging Platforms
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Scalability at Lower Cost
&lt;/h3&gt;

&lt;p&gt;Instead of paying for individual hosting packages, multi-tenant platforms allow multiple blogs to run efficiently on shared resources. This drastically cuts infrastructure costs.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Seamless Updates and Maintenance
&lt;/h3&gt;

&lt;p&gt;No more manually updating themes, plugins, or security patches across dozens of sites. The platform updates once, and all tenants benefit.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Built-in SEO Advantages
&lt;/h3&gt;

&lt;p&gt;Multi-tenant platforms like &lt;a href="https://devdominion.com/" rel="noopener noreferrer"&gt;Dev Dominion&lt;/a&gt; integrate SEO tools directly into the blogging environment. Users can optimize meta tags, URLs, and content structure without needing third-party plugins.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Faster Time to Market
&lt;/h3&gt;

&lt;p&gt;Want to launch a new niche blog? On a multi-tenant platform, you can spin it up in minutes without re-configuring hosting or CMS.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Security and Reliability
&lt;/h3&gt;

&lt;p&gt;Centralized security means vulnerabilities are patched platform-wide. You don’t need to worry about outdated plugins leaving your blog exposed.&lt;/p&gt;

&lt;h2&gt;
  
  
  SEO &amp;amp; Cost Advantages
&lt;/h2&gt;

&lt;p&gt;SEO is critical for anyone starting a blog. With a multi-tenant system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance is better because of optimized shared hosting environments.&lt;/li&gt;
&lt;li&gt;SSL certificates and HTTPS come by default.&lt;/li&gt;
&lt;li&gt;Structured blogging tools help improve search engine ranking.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From a cost perspective, using a service like Dev Dominion (plans starting at just $1/month) is far cheaper than juggling multiple WordPress installs and hosting accounts.&lt;/p&gt;

&lt;p&gt;For reference, research from &lt;a href="https://blog.hubspot.com/" rel="noopener noreferrer"&gt;HubSpot&lt;/a&gt; shows businesses that blog generate 67% more leads than those that don’t, which means investing in a platform that supports SEO directly impacts growth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Cases for Multi-Tenant Platforms
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Agencies &amp;amp; Developers
&lt;/h3&gt;

&lt;p&gt;Agencies running blogs for multiple clients no longer need to maintain individual CMS installations. They can manage all clients from one system.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Media Networks
&lt;/h3&gt;

&lt;p&gt;News sites or niche media brands with multiple sub-blogs benefit from centralized control.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Entrepreneurs &amp;amp; Side Hustlers
&lt;/h3&gt;

&lt;p&gt;Creators can launch multiple niche blogs under one roof, testing ideas without high overhead.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Enterprises
&lt;/h3&gt;

&lt;p&gt;Large organizations can manage regional blogs or product-specific content streams while maintaining brand consistency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dev Dominion: Multi-Tenant Blogging Simplified
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://devdominion.com/" rel="noopener noreferrer"&gt;Dev Dominion&lt;/a&gt; is a modern multi-tenant blogging platform designed for creators, entrepreneurs, and businesses. Its features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom domains to strengthen branding.&lt;/li&gt;
&lt;li&gt;Built-in SEO optimization (meta tags, sitemaps, multilingual support).&lt;/li&gt;
&lt;li&gt;Ecommerce integration for selling digital or physical products.&lt;/li&gt;
&lt;li&gt;Modern templates that are mobile-responsive and customizable.&lt;/li&gt;
&lt;li&gt;Affordable pricing: starting at just $1/month.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Want proof of why multi-tenant is the future? Check out &lt;a href="https://devdominion.com/blog-details/10-reasons-multi-tenant-blog-platforms-are-the-future-of-content" rel="noopener noreferrer"&gt;10 Reasons Multi-Tenant Blog Platforms Are the Future of Content&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges of Multi-Tenant Platforms (and How to Solve Them)
&lt;/h2&gt;

&lt;p&gt;No platform is perfect. Here are some challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Customization limitations: Some multi-tenant systems may restrict access to source code. Solution: Choose a platform with flexible templates and plugin support.&lt;/li&gt;
&lt;li&gt;Migration concerns: Moving from WordPress or custom CMS can feel daunting. Solution: Platforms like Dev Dominion provide migration support and guides.&lt;/li&gt;
&lt;li&gt;Data isolation: Users may worry about data separation. Solution: Multi-tenant architecture keeps each tenant’s data secure and independent.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Future of Blogging: Why Multi-Tenant is Forward-Looking
&lt;/h2&gt;

&lt;p&gt;The web is moving toward service-based platforms where scalability, automation, and AI personalization matter. Future blogging trends include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Headless CMS integrations for omnichannel publishing.&lt;/li&gt;
&lt;li&gt;AI-powered SEO optimization for smarter keyword targeting.&lt;/li&gt;
&lt;li&gt;Personalized content delivery based on reader behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Multi-tenant platforms are perfectly positioned to integrate these innovations, making them the logical choice for the future of content creation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions (FAQs)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q1: What is a multi-tenant blogging platform?&lt;/strong&gt;&lt;br&gt;
A multi-tenant blogging platform allows multiple blogs to run on a single system, sharing resources but keeping data and experiences separate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q2: Is multi-tenant blogging more secure?&lt;/strong&gt;&lt;br&gt;
Yes. Centralized updates and platform-wide security measures reduce vulnerabilities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q3: Can I use my own domain on Dev Dominion?&lt;/strong&gt;&lt;br&gt;
Absolutely. You can connect custom domains easily, giving your blog professional branding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q4: How much does Dev Dominion cost?&lt;/strong&gt;&lt;br&gt;
Plans start at just $1/month for basic blogging and $5/month for full eCommerce integration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q5: Who benefits most from multi-tenant platforms?&lt;/strong&gt;&lt;br&gt;
Agencies, entrepreneurs, media brands, and enterprises managing multiple blogs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Traditional blogging platforms are starting to show their age. In contrast, multi-tenant blogging platforms deliver scalability, security, affordability, and SEO advantages that today’s creators and businesses need.&lt;/p&gt;

&lt;p&gt;If you’re looking to future-proof your blog. Whether you’re an agency managing multiple clients or an individual creator building your brand, a multi-tenant platform like &lt;a href="https://devdominion.com" rel="noopener noreferrer"&gt;Dev Dominion&lt;/a&gt; is your best choice.&lt;/p&gt;

&lt;p&gt;👉 Ready to get started? Explore &lt;a href="https://devdominion.com/pricing" rel="noopener noreferrer"&gt;Dev Dominion’s pricing plans&lt;/a&gt; and launch your blog today.&lt;/p&gt;

&lt;p&gt;Your Brand. Your Blog. Your Domain.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>seo</category>
      <category>beginners</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How Developers Can Use a Free Whois Lookup Tool for Domain Insights</title>
      <dc:creator>Jay Barker</dc:creator>
      <pubDate>Fri, 26 Sep 2025 20:31:51 +0000</pubDate>
      <link>https://dev.to/jaybarker/how-developers-can-use-a-free-whois-lookup-tool-for-domain-insights-1ll4</link>
      <guid>https://dev.to/jaybarker/how-developers-can-use-a-free-whois-lookup-tool-for-domain-insights-1ll4</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Every developer, at some point, runs into a domain they don’t recognize. Maybe it’s a site scraping your content, a client’s domain that’s suddenly down, or a competitor whose hosting setup you’d like to analyze. In moments like these, one simple tool becomes invaluable: Whois Lookup.&lt;/p&gt;

&lt;p&gt;A Whois search gives you the story behind a domain, who registered it, when it was created, where it’s hosted, and even when it will expire. For developers, SEOs, and cybersecurity professionals, this information is a goldmine. The best part? You don’t need expensive tools like Semrush or Ahrefs just to check domain ownership. With the &lt;a href="https://seositechecker.pro/whois" rel="noopener noreferrer"&gt;free Whois Lookup tool&lt;/a&gt;, you can instantly uncover key insights without sign-ups or hidden costs.&lt;/p&gt;

&lt;p&gt;In this article, we’ll break down what Whois Lookup is, why it matters for developers, common use cases, privacy considerations, and how free tools stack up against premium platforms.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Whois Lookup?
&lt;/h2&gt;

&lt;p&gt;At its core, Whois Lookup is a query-and-response protocol. When you type a domain name into a Whois tool, it pulls registration data from domain registries and registrars. This data includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Registrant information (organization or owner, if not hidden)&lt;/li&gt;
&lt;li&gt;Registrar details (the company where the domain was registered)&lt;/li&gt;
&lt;li&gt;Creation and expiration dates&lt;/li&gt;
&lt;li&gt;Nameservers and DNS info&lt;/li&gt;
&lt;li&gt;Hosting provider information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For developers, this information isn’t just trivia. It helps diagnose problems, evaluate opportunities, and make informed technical or business decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Developers Need Whois Lookup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Debugging Domain Issues
&lt;/h3&gt;

&lt;p&gt;When a client reports downtime, a Whois Lookup can reveal if the domain has expired or if its nameservers have changed. Instead of guessing, developers get clear data on the domain’s status.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Checking Domain Age for SEO Trust Signals
&lt;/h3&gt;

&lt;p&gt;Google doesn’t officially say that domain age is a ranking factor, but in practice, older domains often carry more trust. If you’re working on link building or partnerships, checking a domain’s age through Whois helps you avoid spammy sites.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Cybersecurity &amp;amp; Phishing Protection
&lt;/h3&gt;

&lt;p&gt;Many phishing sites look legitimate on the surface but have sketchy domain registrations. Developers can use Whois data to confirm whether a suspicious site was registered yesterday by an unknown registrar.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Competitor Analysis
&lt;/h3&gt;

&lt;p&gt;Ever wondered which hosting provider a competitor is using? Whois records often reveal it. This can give you insights into performance setups or CDN usage that might inspire improvements in your own projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Client Domain Management
&lt;/h3&gt;

&lt;p&gt;For freelance developers and agencies, Whois tools ensure that client domains are actually registered under the client’s name, not a third-party reseller. This transparency prevents future ownership disputes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Scenarios Where Whois Lookup Saves the Day
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Buying Expired Domains
&lt;/h3&gt;

&lt;p&gt;Expired domains can have immense SEO value, especially if they still have backlinks. A quick Whois check reveals whether a domain is truly expired or just parked.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verifying Ownership for Collaborations
&lt;/h3&gt;

&lt;p&gt;When collaborating with new partners, it’s important to know who really owns the site you’re linking to. Whois provides ownership transparency crucial in avoiding shady link exchanges.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tracking Down Malicious or Spam Site
&lt;/h3&gt;

&lt;p&gt;If your app or site is being targeted by spam traffic, Whois helps identify the domain owner or registrar responsible, so you can report or block them effectively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ensuring Proper Registration
&lt;/h3&gt;

&lt;p&gt;Some small businesses lose their domains because they were registered under an agency’s name instead of their own. Developers can use Whois to double-check and secure client ownership.&lt;/p&gt;

&lt;h2&gt;
  
  
  Free Whois Lookup vs. Paid Services
&lt;/h2&gt;

&lt;p&gt;Let’s be real tools like Semrush and Ahrefs are great, but they come with hefty price tags ($99–$199 per month). For many developers, freelancers, and small businesses, that’s not practical.&lt;/p&gt;

&lt;p&gt;Here’s the difference:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Paid Platforms: Provide advanced SEO metrics, backlink profiles, keyword analysis, and competitive research.&lt;/li&gt;
&lt;li&gt;Free Whois Lookup (like &lt;a href="https://seositechecker.pro/whois" rel="noopener noreferrer"&gt;SEO Site Checker&lt;/a&gt;): Instantly delivers raw domain registration data fast, simple, and beginner-friendly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your goal is just to check domain ownership, age, or hosting details, a free tool is often all you need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Whois Privacy &amp;amp; Cloudflare Proxies
&lt;/h2&gt;

&lt;p&gt;Now, you might wonder: Why don’t I always see the real owner in a Whois result?&lt;/p&gt;

&lt;p&gt;That’s because of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Whois Privacy Services – Many registrars (like Namecheap or GoDaddy) let owners hide their personal details. Instead of seeing their name/email, you’ll see a proxy service.&lt;/li&gt;
&lt;li&gt;Cloudflare and Other Proxies – When domains are routed through Cloudflare or similar CDNs, the Whois data often reflects proxy servers instead of the actual hosting provider.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 While this limits transparency, you can still get valuable insights such as registrar, domain age, expiration date, and DNS records.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step-by-Step: How to Use a Free Whois Lookup
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Visit SEO Site Checker’s &lt;a href="https://seositechecker.pro/whois" rel="noopener noreferrer"&gt;Whois Lookup&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Enter the domain you want to check.&lt;/li&gt;
&lt;li&gt;Click search, and in seconds you’ll see registration details, registrar info, and domain age.&lt;/li&gt;
&lt;li&gt;If privacy protection is enabled, note the registrar and nameservers for clues.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It’s quick, free, and requires no login making it the perfect tool to keep bookmarked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices When Using Whois Data
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Respect privacy: Just because data is visible doesn’t mean it should be misused.&lt;/li&gt;
&lt;li&gt;Verify across sources: If something looks suspicious, cross-check with DNS record lookups.&lt;/li&gt;
&lt;li&gt;Keep records: When doing audits, save Whois reports for future reference.&lt;/li&gt;
&lt;li&gt;Combine with other tools: Pair Whois data with &lt;a href="https://seositechecker.pro/find-dns-record" rel="noopener noreferrer"&gt;DNS Record Lookup&lt;/a&gt; or &lt;a href="https://seositechecker.pro/domain-age-checker" rel="noopener noreferrer"&gt;Domain Age Checker&lt;/a&gt; for a complete picture.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;For developers, Whois Lookup isn’t just another tool it’s a lens into the hidden details of the web. From debugging client issues to investigating competitors and safeguarding against phishing, it provides insights you can act on immediately.&lt;/p&gt;

&lt;p&gt;The best part? You don’t need to spend hundreds on enterprise SEO suites to get this data. With the &lt;a href="https://seositechecker.pro/whois" rel="noopener noreferrer"&gt;free Whois Lookup Tool&lt;/a&gt;, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check any domain’s registrar, age, and hosting instantly&lt;/li&gt;
&lt;li&gt;Access data without signups or hidden charges&lt;/li&gt;
&lt;li&gt;Save time and money while still getting actionable insights&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Next time you come across an unfamiliar domain, don’t guess, run a Whois Lookup in seconds.&lt;/p&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
