Changelog
- 1.0.0, 22 October 2026: first release
kits / search-and-share
Head tags, robots.txt, sitemaps, structured data and share image sizes so search engines and chat apps show your site properly.
MIT License
Copyright (c) 2026 Snowkit
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.Version 1.0.0
Everything a site needs so search engines can find and understand its pages, and so links look right when people share them. It has a complete head template, robots.txt and sitemap files, structured data templates for eight common page types, a share image size table with safe zones, a guide to writing titles and descriptions, and two checklists: one for each page and one for launch and indexing. Every JSON and XML file is valid as shipped.
No SEO background is needed. Each file explains what to change and why.
head-tags.html, copy the tags into your page template and replace the [placeholders]. Read head-tags-guide.md for what you can remove.robots/robots.txt to your site root and change the paths and sitemap URL.share-image-sizes.md, and point og:image at it.structured-data/ and add them.launch-indexing-checklist.md from the top.| File | What it is |
|---|---|
README.md | This file |
LICENSE.txt | MIT licence |
CHANGELOG.md | Version history |
head-tags.html | Complete head template: title, description, canonical, robots, Open Graph, X card, theme colour, icons and a basic JSON-LD block |
head-tags-guide.md | What each tag in the template does, which ones to keep, and common mistakes |
robots/robots.txt | A sensible default robots.txt |
robots/robots-variants.md | The default explained, plus variants for staging, URL parameters, AI training crawlers and crawl delay |
sitemaps/sitemap.xml | Example sitemap with image and language alternate extensions |
sitemaps/sitemap-index.xml | Example sitemap index for larger sites |
sitemaps/sitemap-guide.md | What to include, which tags matter, escaping, submitting and checking |
structured-data/README.md | How to add JSON-LD, what each template can do in search, and how to test it |
structured-data/organization.json | Organization template |
structured-data/website.json | WebSite template with SearchAction |
structured-data/article.json | Article template |
structured-data/product.json | Product template with offer, shipping and returns |
structured-data/faq-page.json | FAQPage template |
structured-data/breadcrumb-list.json | BreadcrumbList template |
structured-data/local-business.json | LocalBusiness template with address, location and opening hours |
structured-data/software-application.json | SoftwareApplication template |
share-image-sizes.md | Share image sizes by platform, safe zones, text and file advice |
titles-and-descriptions.md | Length guidance, patterns and examples for titles, descriptions and share text |
seo-checklist.md | On-page checklist for each page template |
launch-indexing-checklist.md | Launch checklist: staging blocks, migrations, Google Search Console, Bing Webmaster Tools, rendering and canonical issues |
This kit covers the technical and on-page groundwork. It can't make a page rank: that depends on the content, the competition and links from other sites, none of which a template controls. Search engines and social platforms change their rules and image sizes regularly, so confirm platform-specific details with their current documentation before a big launch.
MIT License. See LICENSE.txt.
head-tags.html is a complete <head> for a typical page. Copy the tags into your layout or template, replace every [placeholder], and delete the lines you don't need. This guide explains each group so you know what is safe to remove.
| Tag | Keep? | Notes |
|---|---|---|
<meta charset="utf-8"> | Always | Must be in the first 1024 bytes of the page |
<meta name="viewport"> | Always | Without it, phones render the desktop layout zoomed out |
<title> | Always | One per page, unique across the site. See titles-and-descriptions.md |
<meta name="description"> | Always | Not a ranking factor, but often used as the snippet under your link |
<link rel="canonical"> | Always | The one preferred URL for this content. Absolute URL, HTTPS, your chosen www or non-www form |
<meta name="robots"> | Usually | The values shown let search engines use large image previews and full snippets. Use noindex on pages that shouldn't appear in search |
Only keep the hreflang lines if the page exists in more than one language or region. Each language version lists every version, including itself, and x-default points to the version for everyone else (often a language picker or the main language). If your site is in one language, delete both lines.
Open Graph tags control the preview card when someone shares your link in chat apps, social networks and many other places. Most platforms read them, including Facebook, LinkedIn, Slack, Discord, WhatsApp, iMessage and Telegram.
| Tag | Notes |
|---|---|
og:type | website for most pages, article for blog posts and news. Articles can add article:published_time and article:author |
og:title | Can differ from <title>. Drop the site name suffix here; og:site_name carries it |
og:description | One sentence. Shorter than the meta description works better in cards |
og:url | Same as the canonical URL |
og:image | Absolute HTTPS URL. 1200 x 630 px suits almost everywhere. See share-image-sizes.md |
og:image:width / height | Lets platforms render the card before downloading the image |
og:image:alt | Read by screen readers on platforms that support it |
og:locale | en_GB, en_US, fr_FR and so on |
X reads Open Graph tags for title, description and image if its own tags are missing, so you only need:
twitter:card set to summary_large_image for a wide image, or summary for a small square thumbnailtwitter:site and twitter:creator if you have accounts to credit. Delete them if nottheme-color tints the browser interface on some mobile browsers. The two lines give separate light and dark values. Delete the media attribute and one line if you only want one colour.favicon.ico at 32 x 32 still matters for older browsers and some tools that fetch it directly.icon.svg gives a sharp icon at any size in modern browsers. It can include a dark mode style.apple-touch-icon.png is 180 x 180 px, with no transparency. It is used when someone adds your site to their home screen.site.webmanifest holds the app name and larger icons (192 and 512 px) for Android and installable web apps. Delete the line if you don't have one.The small WebPage block at the end is a safe default. For specific page types, replace it with one of the templates in structured-data/ (see structured-data/README.md).
og:image or canonical. Both must be absolute.noindex left on from a staging site.robots.txt, so platforms can't fetch them.<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>[Page title] | [Site name]</title>
<meta name="description" content="[What this page offers, in one or two plain sentences of about 150 characters.]">
<link rel="canonical" href="https://example.com/[page-path]">
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
<link rel="alternate" hreflang="en" href="https://example.com/[page-path]">
<link rel="alternate" hreflang="x-default" href="https://example.com/[page-path]">
<meta property="og:type" content="website">
<meta property="og:site_name" content="[Site name]">
<meta property="og:title" content="[Share title, can be warmer than the page title]">
<meta property="og:description" content="[Share description, one sentence that makes someone want to click]">
<meta property="og:url" content="https://example.com/[page-path]">
<meta property="og:image" content="https://example.com/[share-images/page-name].png">
<meta property="og:image:type" content="image/png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="[Plain description of what the share image shows]">
<meta property="og:locale" content="en_GB">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@[site account]">
<meta name="twitter:creator" content="@[author account]">
<meta name="theme-color" content="[#ffffff]" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="[#111111]" media="(prefers-color-scheme: dark)">
<link rel="icon" href="/favicon.ico" sizes="32x32">
<link rel="icon" href="/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="manifest" href="/site.webmanifest">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebPage",
"name": "[Page title]",
"description": "[Same as the meta description]",
"url": "https://example.com/[page-path]",
"isPartOf": {
"@type": "WebSite",
"name": "[Site name]",
"url": "https://example.com/"
}
}
</script>
</head>For a new site, a redesign or a move to a new domain. Work through it in order. The "before launch" section catches the mistakes that are cheap to fix now and expensive to fix after search engines have crawled the wrong thing.
Site: [https://example.com] Launch date: [date] Owner: [name]
Disallow: / in robots.txt, noindex meta tags, X-Robots-Tag headers, password protection, CMS "discourage search engines" settings.https://example.com or https://www.example.com) and redirect the other to it with a 301.http:// redirects to https:// in one hop.404, not 200.seo-checklist.md.robots.txt is ready for production (see robots/robots-variants.md).sitemap.xml lists production URLs only (see sitemaps/sitemap-guide.md).https://example.com/robots.txt and read it. Confirm it is the production version.noindex.X-Robots-Tag on HTML pages: curl -sI https://example.com/ | grep -i robots.https://example.com/ and verify it with an HTML file or meta tag.sitemap.xml, Submit.Search engines need to see your content, not an empty app shell.
In the Pages report (Indexing, Pages), these reasons point to canonical problems:
| Report reason | What it usually means | What to do |
|---|---|---|
| Duplicate without user-selected canonical | Similar pages with no canonical tag | Add canonical tags |
| Duplicate, Google chose different canonical than user | Google disagrees with your canonical, often because content is near-identical or internal links point elsewhere | Make internal links, sitemap and canonical all point to the same URL; make pages more distinct |
| Alternate page with proper canonical tag | Working as intended | Nothing, if the canonical is the page you want |
| Page with redirect | A redirected URL is still being linked or listed | Update links and remove it from the sitemap |
| Crawled, currently not indexed | Google fetched it but chose not to index it yet | Improve quality and internal links; wait. Common on new sites |
| Discovered, currently not indexed | Google knows the URL but hasn't crawled it yet | Usually time and internal links. Check server speed |
| Excluded by noindex tag | A noindex is present | Remove it if the page should be indexed |
| Blocked by robots.txt | Disallowed in robots.txt | Allow it if the page should be indexed |
| When | Check |
|---|---|
| Day 1 | Sitemap status shows "Success". URL Inspection shows home page indexable |
| Day 3 | Search the exact site: site:example.com. Some pages should appear (this is a rough check, not a count) |
| Week 1 | Pages report: are indexed pages rising? Any unexpected "Excluded" reasons? |
| Week 1 | Crawl stats (Settings, Crawl stats): any spike in server errors or slow responses? |
| Week 2 | Core Web Vitals report starts filling in for busier sites |
| Week 2 | For a migration: old URLs dropping out, new ones replacing them. Spot-check rankings for top pages |
| Week 4 | Performance report: clicks and impressions trend. Compare against the old site for a migration |
| Week 4 | Fix the most common issues from the Pages report and click "Validate fix" |
| Item | Done by | Date |
|---|---|---|
| Staging blocks removed and rechecked | ||
| Search Console verified, sitemap submitted | ||
| Bing Webmaster Tools verified, sitemap submitted | ||
| Rendering checked on 3 key pages | ||
| Redirects tested (migration only) |
Run this for each page template (home, category, product, article, landing page) and for your ten most important pages. Most problems live in templates, so fixing a template fixes hundreds of pages at once.
200 to a plain request (no login, no geo-block, no bot challenge for search crawlers).robots.txt.noindex in a meta tag or X-Robots-Tag header, unless intended.<a href="..."> links, not click handlers on divs or buttons.<link rel="canonical"> is present, absolute, and points to the preferred URL of this page.http:// and https://, www and non-www, and trailing slash variants all redirect (301) to the one canonical form.utm_ and similar) canonicalise to the clean URL.?page=2) canonicalise to themselves, not to page 1.<title> and meta description (see titles-and-descriptions.md).<h1>, describing the page's main topic.h2, h3) follow the structure of the content and aren't used just for styling.noindex.404).rel="sponsored" or rel="ugc".alt text. Decorative images have alt="".blue-widget-side.jpg, not IMG_0042.jpg).width and height attributes are set to prevent layout shifts.loading="lazy". The main image near the top doesn't.structured-data/ is on the page.head-tags-guide.md).share-image-sizes.md.hreflang annotations are complete and reciprocal, with x-default.lang attribute on <html> matches the page language.| Template | Example URL | Reviewer | Date | Issues found | Fixed |
|---|---|---|---|---|---|
| Home | |||||
| Category | |||||
| Product | |||||
| Article | |||||
| Landing page |
When someone shares your link, most platforms show a card with an image, title and description. The image comes from your og:image tag (or twitter:image on X, if set). This page gives sizes that work across platforms, safe zones so nothing important gets cropped, and file advice.
Platforms change these often, and many don't publish exact specs. The values below reflect common published guidance as of October 2026. Rows marked Changes often are the ones most likely to move. Confirm with each platform's current documentation or preview tool before a big launch.
Make one image per page at 1200 x 630 px, PNG or JPEG, under 1 MB (under 300 KB if you care about WhatsApp), with the key content inside the centre 630 x 630 px square. That works well almost everywhere.
| Platform | Recommended size | Aspect ratio | Minimum | Max file size | Notes | Stability |
|---|---|---|---|---|---|---|
| Open Graph (general) | 1200 x 630 | 1.91:1 | 600 x 315 for large cards | Keep under 1 MB | The baseline most platforms read | Stable |
| 1200 x 630 | 1.91:1 | 600 x 315 for a large card; smaller images show as a thumbnail | 8 MB | Caches aggressively. Use the Sharing Debugger to refresh | Stable | |
| 1200 x 627 | 1.91:1 | 1200 wide recommended | 5 MB | 1200 x 630 looks the same. Use Post Inspector to refresh the cache | Changes often | |
X, summary_large_image | 1200 x 628 | about 1.91:1 (displays close to 2:1) | 300 x 157 | 5 MB | Reads og:image if no twitter:image. Has shown cards with the title over the image, so keep text away from the bottom edge | Changes often |
X, summary | 240 x 240 or larger | 1:1 | 144 x 144 | 5 MB | Small square thumbnail beside the text | Changes often |
| Slack | Uses Open Graph | 1.91:1 | No published minimum | No published limit | Shows a smaller image in unfurls. Text in the image must still be readable at a small size | Changes often |
| Discord | Uses Open Graph | 1.91:1 | No published minimum | No published limit | Large image for summary_large_image, otherwise a thumbnail. theme-color sets the embed's accent colour | Changes often |
| Uses Open Graph | 1.91:1, often shown as a square thumbnail | No published minimum | Images over about 300 KB may not show | Often crops to a centre square. File size is the most common reason previews fail | Changes often | |
| iMessage | Uses Open Graph | 1.91:1 | No published minimum | No published limit | Shows large previews. Also uses your apple-touch-icon in some layouts | Changes often |
| Telegram | Uses Open Graph | 1.91:1 | No published minimum | No published limit | Large image when wide enough, otherwise a thumbnail | Changes often |
| 1000 x 1500 | 2:3 | 600 wide | 20 MB | Uses a tall image. Set a separate pin image on the page if Pinterest matters to you | Changes often | |
| Fediverse servers | Uses Open Graph | 1.91:1 | No published minimum | Set by each server | Fetched by each server separately | Changes often |
Different platforms crop the same image differently. Design for the smallest common area.
+------------------------------------------------------------+
| 1200 x 630 |
| +--------------------------------------+ |
| | Text-safe area: 1080 x 550 | |
| | +----------------------------+ | |
| | | Centre square: 630 x 630 | | |
| | | (logo, key words, face) | | |
| | +----------------------------+ | |
| +--------------------------------------+ |
+------------------------------------------------------------+
| Choice | Advice |
|---|---|
| Format | PNG for text, logos and flat graphics. JPEG for photos. WebP is widely supported now, but some older crawlers and apps still skip it. Use PNG or JPEG for the og:image to be safe |
| Size | Aim for under 300 KB. Over 1 MB is slower to fetch and some platforms give up |
| Colour | sRGB. Other colour profiles can look washed out |
| Transparency | Avoid. Transparent areas can render black or white depending on the app |
| URL | Absolute HTTPS URL, publicly reachable, not blocked by robots.txt, fast to respond |
| Changes | Give a changed image a new file name (share-v2.png). Platforms cache by URL, sometimes for weeks |
og:image URL opens directly in a private browser window.og:image:width and og:image:height match the real file.og:image:alt describes the image.The page title and meta description are often the first words anyone reads from your site: in search results, in browser tabs, in bookmarks and in share cards. They decide whether someone clicks.
Search engines cut text by pixel width, not character count, so these are guides rather than hard limits. Wide letters (W, M) use more space than narrow ones (i, l).
| Text | Aim for | Usually cut after | Notes |
|---|---|---|---|
Page title (<title>) | 50 to 60 characters | About 600 px wide on desktop, roughly 60 characters | Put the important words first so a cut doesn't lose them |
| Meta description | 120 to 155 characters | About 155 to 160 characters on desktop, fewer on mobile | Front-load the useful part. Mobile often shows about 120 |
og:title | 40 to 70 characters | Varies by platform | Often shown over two lines in cards |
og:description | 60 to 110 characters | Many cards show one or two lines | Some platforms hide it entirely |
| URL slug | 3 to 5 words | Shown shortened in results | Lowercase, hyphens, no dates unless the content is dated |
Google rewrites titles and descriptions when it thinks another piece of text on the page matches the search better. You can't stop this, but titles and descriptions that accurately match the page are rewritten far less often.
Pattern: [Specific topic or offer] | [Site name] or [Specific topic]: [Benefit or detail] | [Site name]
Rules:
| or -. Drop it on long titles if space is tight; Google often shows your site name separately anyway.Examples:
| Page type | Weak | Better |
|---|---|---|
| Product | Product Page - Example Co | Blue Widget, 40 cm, Waterproof - Example Co |
| Blog post | Blog - Example Co | How to Fix a Leaking Widget in 10 Minutes - Example Co |
| Category | Widgets | Garden Widgets: Waterproof and Weatherproof - Example Co |
| Local service | Home | Widget Repair in Leeds, Same-Week Visits - Example Co |
| Pricing | Pricing | Pricing and Plans - Example Co |
| Docs page | Getting Started | Install the Example CLI on macOS, Windows and Linux - Example Docs |
Pattern: what the page offers, one concrete detail, and what the reader can do next.
Rules:
Examples:
| Page | Description |
|---|---|
| Product | Waterproof blue widget, 40 cm, made in Leeds. Ships in 2 working days, with 30-day returns. See sizes and care guide. |
| Blog post | A leaking widget is usually a worn seal. Here's how to find it, replace it and test the fix in about ten minutes, with photos. |
| Local service | Widget repair across Leeds and Bradford. Book a same-week visit online, with fixed prices shown before you confirm. |
| Docs page | Install the Example command-line tool with a package manager or a single download. Covers macOS, Windows and Linux. |
Share cards are read in a feed, next to a friend's name, not in a list of search results. They can be warmer than search titles.
og:title. The card shows your domain.<title> of roughly 50 to 60 characters.robots.txt lives at the root of your domain (https://example.com/robots.txt) and tells crawlers which paths they may fetch. Each subdomain needs its own file.
Two things it does not do:
<meta name="robots" content="noindex"> or an X-Robots-Tag: noindex header.User-agent: *
Disallow: /admin/
Disallow: /account/
Disallow: /cart/
Disallow: /checkout/
Disallow: /search?
Sitemap: https://example.com/sitemap.xml
What each line is for:
| Line | Why |
|---|---|
User-agent: * | The rules apply to every crawler that doesn't have its own group |
/admin/, /account/ | Pages behind a login. Crawlers waste time on them and get redirected |
/cart/, /checkout/ | Personal, empty for a crawler and never useful in search |
/search? | Your internal search results. They create endless near-duplicate pages. The ? means the search page itself stays crawlable but result URLs don't |
Sitemap: | Full URL of your sitemap or sitemap index. You can list more than one |
Change the paths to match your site, and delete any you don't have. Rules are prefix matches: Disallow: /cart/ blocks /cart/ and everything under it, but not /cartoons. A rule without the trailing slash, such as Disallow: /cart, would block /cartoons too.
Search engines render pages like a browser. If you block your CSS, JavaScript, images or the API your pages call to fetch content, they see a broken page. Don't disallow /assets/, /static/, /_next/, /wp-content/ or similar.
For a small site with nothing private, this is a fine robots.txt:
User-agent: *
Disallow:
Sitemap: https://example.com/sitemap.xml
An empty Disallow: means "nothing is blocked". Having no robots.txt at all has the same effect, but the file is a convenient place to list your sitemap.
Block all crawling on staging, and protect it with a password as well. robots.txt alone won't keep a staging site out of search if someone links to it.
User-agent: *
Disallow: /
Add X-Robots-Tag: noindex to every response on staging too. The biggest risk is copying this file to production by accident. Generate robots.txt per environment in your build, and check the live file on launch day.
Faceted navigation (filters, sorting, tracking parameters) can create thousands of duplicate URLs. Google and Bing support * as a wildcard and $ for the end of a URL:
User-agent: *
Disallow: /*?*sort=
Disallow: /*?*sessionid=
Disallow: /*.pdf$
The first two block any URL with that parameter, in any position. The last blocks every URL ending in .pdf. Use these carefully: one wrong wildcard can block your whole catalogue. Prefer canonical tags for duplicate pages you still want crawled.
Some companies use separate crawlers, or separate user-agent tokens, to collect content for training AI models. You can block those while still allowing normal search crawling:
User-agent: Google-Extended
Disallow: /
User-agent: Applebot-Extended
Disallow: /
User-agent: CCBot
Disallow: /
User-agent: *
Disallow: /admin/
Sitemap: https://example.com/sitemap.xml
Notes:
Google-Extended and Applebot-Extended are control tokens, not separate crawlers. Blocking them doesn't affect Google Search or Apple's search features.User-agent: [Crawler name]
Crawl-delay: 10
Bing and some others respect Crawl-delay (seconds between requests). Google ignores it; Google adjusts its crawl rate automatically based on how your server responds.
* group. If you add a group for one crawler, repeat any general rules it should also follow.Allow and Disallow both match, Google uses the longest (most specific) rule.200. A 5xx error on robots.txt can make Google pause crawling your whole site.https://example.com/robots.txt in a browser and read what is actually live.User-agent: *
Disallow: /admin/
Disallow: /account/
Disallow: /cart/
Disallow: /checkout/
Disallow: /search?
Sitemap: https://example.com/sitemap.xmlA sitemap is a list of the URLs you want search engines to find. It doesn't force anything into the index, but it helps crawlers discover new and updated pages faster, especially on new sites with few links pointing to them.
| File | Use it when |
|---|---|
sitemap.xml | Your site has fewer than 50,000 URLs and the file is under 50 MB uncompressed. Most sites |
sitemap-index.xml | You have more URLs than that, or want separate sitemaps per section (pages, blog, products) so you can see indexing per section in Search Console |
Both use the standard sitemaps.org format, which Google, Bing and other engines read.
Include a URL only if all of these are true:
200 (not a redirect, not a 404).<link rel="canonical"> points to itself).noindex.robots.txt.Leave out: redirects, paginated filter combinations, internal search results, thank-you pages, login pages, staging URLs and URLs with tracking parameters.
| Tag | Required | Notes |
|---|---|---|
<loc> | Yes | Absolute URL, same protocol and host as the canonical (https://example.com, not a mix of www and non-www) |
<lastmod> | Recommended | Date the content last changed meaningfully. YYYY-MM-DD or a full timestamp with time zone |
<changefreq> | No | Google ignores it. Leave it out |
<priority> | No | Google ignores it. Leave it out |
Keep lastmod honest. Set it when the main content changes, not on every build or when a footer link changes. Search engines learn to ignore lastmod on sites where it always says "today".
image:image): lists important images on a page. Useful for image-heavy pages whose images load by JavaScript. Most sites don't need it.xhtml:link): an alternative to hreflang tags in the HTML. Each language version lists every version, including itself, plus x-default. Use one method, not both, so they can't disagree.URLs in a sitemap must be XML-escaped. The most common mistake is a raw & in a query string:
| Character | Write it as |
|---|---|
& | & |
' | ' |
" | " |
< | < |
> | > |
Non-ASCII characters in paths should be percent-encoded, for example https://example.com/caf%C3%A9.
https://example.com/sitemap.xml. A sitemap can only list URLs on its own host and below its own folder, unless you submit it through Search Console for the whole property.Sitemap: line with the full URL to robots.txt.launch-indexing-checklist.md.Content-Type: application/xml or text/xml and status 200.You can also gzip a sitemap (sitemap.xml.gz). The 50 MB limit applies to the uncompressed size.
For anything beyond a handful of pages, generate the sitemap from your routes or CMS on each build or on request. Most frameworks and CMSs have a plugin or built-in option. Hand-written sitemaps go stale within weeks.
Whatever generates it, check:
localhost or a preview URL.noindex.lastmod comes from the content's real modified date.python -c "import xml.dom.minidom,sys; xml.dom.minidom.parse(sys.argv[1])" sitemap.xml locally.200, be canonical and be indexable.<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>https://example.com/sitemaps/pages.xml</loc>
<lastmod>2026-10-20</lastmod>
</sitemap>
<sitemap>
<loc>https://example.com/sitemaps/blog.xml</loc>
<lastmod>2026-10-18</lastmod>
</sitemap>
<sitemap>
<loc>https://example.com/sitemaps/products-1.xml</loc>
<lastmod>2026-10-21</lastmod>
</sitemap>
<sitemap>
<loc>https://example.com/sitemaps/products-2.xml</loc>
<lastmod>2026-10-21</lastmod>
</sitemap>
</sitemapindex><?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
<url>
<loc>https://example.com/</loc>
<lastmod>2026-10-20</lastmod>
</url>
<url>
<loc>https://example.com/pricing</loc>
<lastmod>2026-10-14</lastmod>
</url>
<url>
<loc>https://example.com/about</loc>
<lastmod>2026-09-02</lastmod>
</url>
<url>
<loc>https://example.com/blog/how-to-choose-a-widget</loc>
<lastmod>2026-10-18T09:30:00+00:00</lastmod>
<image:image>
<image:loc>https://example.com/images/blog/choose-a-widget.jpg</image:loc>
</image:image>
</url>
<url>
<loc>https://example.com/products/blue-widget</loc>
<lastmod>2026-10-10</lastmod>
</url>
<url>
<loc>https://example.com/en/contact</loc>
<lastmod>2026-08-21</lastmod>
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/contact"/>
<xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/contact"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/en/contact"/>
</url>
<url>
<loc>https://example.com/fr/contact</loc>
<lastmod>2026-08-21</lastmod>
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/contact"/>
<xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/contact"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/en/contact"/>
</url>
</urlset>Structured data is a block of JSON-LD in your page that describes what the page is about in a format machines can read: this is an article by this person, this is a product at this price, this business opens at nine. Search engines use it to understand pages and, for some types, to show richer results.
Each .json file in this folder is one template, valid JSON, ready to fill in.
Paste the JSON inside a script tag anywhere in the page, usually in the <head>:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": []
}
</script>
Rules that apply to every template:
Article and BreadcrumbList. Keep each as its own script tag, or combine them in an @graph array.\". If your template engine inserts values, use its JSON encoder, not plain string concatenation, so a quote in a product name can't break the page or inject script.| File | Use on | What it can do in Google | Notes |
|---|---|---|---|
organization.json | Home page or about page, once per site | Helps with the logo and details in knowledge panels | Use the @id (https://example.com/#organization) to reference it from other blocks instead of repeating details |
website.json | Home page only | Helps Google pick your site name | Google retired the sitelinks search box in 2024, so SearchAction no longer shows a search box there. It is harmless and other consumers may use it. Remove it if you have no site search |
article.json | Blog posts, news, guides | Better title, date and image handling in results and news surfaces | headline should match the visible H1. Use real author pages for author.url. Images in 16:9, 4:3 and 1:1, at least 1200 px wide |
product.json | Product detail pages | Price, availability, shipping and returns in results and shopping surfaces | Every offer value must match the page. Update availability when stock changes. Remove gtin13 if you have no barcode number |
faq-page.json | A page whose main content is a list of questions and answers | Since 2023 Google shows FAQ rich results only for well-known government and health sites | Still valid markup that other engines and tools read. Don't use it for user-submitted Q&A (that is QAPage) or for marketing copy in question form |
breadcrumb-list.json | Any page below the home page | Can replace the URL in results with a readable trail; where it shows varies by device and changes over time | The last item has no item URL because it is the current page. Must match the visible breadcrumb trail |
local-business.json | The home or contact page of a business with a physical location or service area | Supports local results, but your Google Business Profile matters far more | Use the most specific type that fits: Restaurant, Dentist, Plumber, Store and many more are listed on schema.org. One block per location, on that location's page |
software-application.json | App or software landing page | Can show rating and price | Google expects offers and either aggregateRating or review. Only include ratings that are real and shown on the page. Use MobileApplication or WebApplication if more accurate |
2026-10-18 or 2026-10-18T09:30:00+01:00. Include the time zone when you include a time."24.00", not "GBP 24" or a symbol. Currency goes in priceCurrency as a three-letter ISO code.GB, US, DE).https://schema.org/InStock.HH:MM. For a day you're closed, leave it out. For one-off holiday hours, add a block with validFrom and validThrough.Giving Organization and WebSite an @id lets other blocks point to them:
"publisher": { "@id": "https://example.com/#organization" }
This keeps details in one place. The @id is an identifier, not a page that needs to exist, but it should stay the same forever.
{
"@context": "https://schema.org",
"@type": "Article",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://example.com/blog/[article-slug]"
},
"headline": "[Article headline, matching the visible H1]",
"description": "[One or two sentence summary]",
"image": [
"https://example.com/images/blog/[article-slug]-16x9.jpg",
"https://example.com/images/blog/[article-slug]-4x3.jpg",
"https://example.com/images/blog/[article-slug]-1x1.jpg"
],
"datePublished": "2026-10-18T09:30:00+01:00",
"dateModified": "2026-10-20T14:00:00+01:00",
"author": [
{
"@type": "Person",
"name": "[Author name]",
"url": "https://example.com/authors/[author-slug]"
}
],
"publisher": {
"@type": "Organization",
"@id": "https://example.com/#organization",
"name": "Example Co",
"logo": {
"@type": "ImageObject",
"url": "https://example.com/images/logo-512.png"
}
},
"inLanguage": "en-GB",
"wordCount": 1450
}{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://example.com/"
},
{
"@type": "ListItem",
"position": 2,
"name": "[Section name, for example Guides]",
"item": "https://example.com/[section]/"
},
{
"@type": "ListItem",
"position": 3,
"name": "[Current page title]"
}
]
}{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "[First question, exactly as shown on the page]",
"acceptedAnswer": {
"@type": "Answer",
"text": "[Full answer, exactly as shown on the page. Simple HTML such as <a href=\"https://example.com/help\">links</a> and <strong>bold</strong> is allowed.]"
}
},
{
"@type": "Question",
"name": "[Second question]",
"acceptedAnswer": {
"@type": "Answer",
"text": "[Second answer]"
}
},
{
"@type": "Question",
"name": "[Third question]",
"acceptedAnswer": {
"@type": "Answer",
"text": "[Third answer]"
}
}
]
}{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"@id": "https://example.com/#business",
"name": "Example Co",
"description": "[What the business does and where, in one or two sentences]",
"url": "https://example.com/",
"telephone": "[+44 20 0000 0000]",
"email": "[email protected]",
"image": [
"https://example.com/images/shopfront-16x9.jpg",
"https://example.com/images/shopfront-4x3.jpg",
"https://example.com/images/shopfront-1x1.jpg"
],
"logo": "https://example.com/images/logo-512.png",
"priceRange": "[Price range, for example 10-50 GBP]",
"address": {
"@type": "PostalAddress",
"streetAddress": "[Street address]",
"addressLocality": "[Town or city]",
"addressRegion": "[County, state or region]",
"postalCode": "[Postcode]",
"addressCountry": "[Two-letter country code]"
},
"geo": {
"@type": "GeoCoordinates",
"latitude": "[Latitude to 5 decimal places]",
"longitude": "[Longitude to 5 decimal places]"
},
"hasMap": "https://example.com/[link-to-your-map-listing]",
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
"opens": "09:00",
"closes": "17:30"
},
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": "Saturday",
"opens": "10:00",
"closes": "16:00"
}
],
"areaServed": "[Town, region or list of areas you serve]",
"sameAs": [
"https://www.facebook.com/[page-handle]",
"https://www.instagram.com/[account]"
]
}{
"@context": "https://schema.org",
"@type": "Organization",
"@id": "https://example.com/#organization",
"name": "Example Co",
"legalName": "[Registered company name]",
"url": "https://example.com/",
"logo": {
"@type": "ImageObject",
"url": "https://example.com/images/logo-512.png",
"width": 512,
"height": 512
},
"description": "[One or two sentences on what the organisation does]",
"email": "[email protected]",
"telephone": "[+44 20 0000 0000]",
"address": {
"@type": "PostalAddress",
"streetAddress": "[Street address]",
"addressLocality": "[Town or city]",
"addressRegion": "[County, state or region]",
"postalCode": "[Postcode]",
"addressCountry": "[Two-letter country code, for example GB]"
},
"sameAs": [
"https://www.linkedin.com/company/[company-handle]",
"https://github.com/[org-handle]",
"https://x.com/[account]"
],
"contactPoint": {
"@type": "ContactPoint",
"contactType": "customer support",
"email": "[email protected]",
"availableLanguage": ["en"]
}
}{
"@context": "https://schema.org",
"@type": "Product",
"@id": "https://example.com/products/blue-widget#product",
"name": "[Product name]",
"description": "[Plain description of the product, matching the page]",
"image": [
"https://example.com/images/products/blue-widget-1x1.jpg",
"https://example.com/images/products/blue-widget-4x3.jpg",
"https://example.com/images/products/blue-widget-16x9.jpg"
],
"sku": "[SKU]",
"gtin13": "[13-digit GTIN, or remove this line]",
"brand": {
"@type": "Brand",
"name": "[Brand name]"
},
"offers": {
"@type": "Offer",
"url": "https://example.com/products/blue-widget",
"price": "[Price as a number, for example 24.00]",
"priceCurrency": "[Three-letter currency code, for example GBP]",
"availability": "https://schema.org/InStock",
"itemCondition": "https://schema.org/NewCondition",
"priceValidUntil": "[YYYY-MM-DD, or remove this line]",
"seller": {
"@id": "https://example.com/#organization"
},
"shippingDetails": {
"@type": "OfferShippingDetails",
"shippingRate": {
"@type": "MonetaryAmount",
"value": "[Shipping cost as a number]",
"currency": "[Three-letter currency code]"
},
"shippingDestination": {
"@type": "DefinedRegion",
"addressCountry": "[Two-letter country code]"
},
"deliveryTime": {
"@type": "ShippingDeliveryTime",
"handlingTime": {
"@type": "QuantitativeValue",
"minValue": 0,
"maxValue": 1,
"unitCode": "DAY"
},
"transitTime": {
"@type": "QuantitativeValue",
"minValue": 1,
"maxValue": 3,
"unitCode": "DAY"
}
}
},
"hasMerchantReturnPolicy": {
"@type": "MerchantReturnPolicy",
"applicableCountry": "[Two-letter country code]",
"returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow",
"merchantReturnDays": 30,
"returnMethod": "https://schema.org/ReturnByMail",
"returnFees": "https://schema.org/ReturnFeesCustomerResponsibility"
}
}
}{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "[App name]",
"description": "[What the app does, in one or two sentences]",
"url": "https://example.com/app",
"applicationCategory": "BusinessApplication",
"operatingSystem": "[Web, Windows, macOS, iOS, Android]",
"softwareVersion": "[2.4.1]",
"datePublished": "[YYYY-MM-DD of first release]",
"screenshot": "https://example.com/images/app-screenshot.png",
"image": "https://example.com/images/app-icon-512.png",
"publisher": {
"@id": "https://example.com/#organization"
},
"offers": {
"@type": "Offer",
"price": "[Price as a number]",
"priceCurrency": "[Three-letter currency code]",
"url": "https://example.com/pricing"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "[Average of real reviews shown on the page, or remove this block]",
"ratingCount": "[Number of real ratings]",
"bestRating": "5",
"worstRating": "1"
}
}{
"@context": "https://schema.org",
"@type": "WebSite",
"@id": "https://example.com/#website",
"name": "Example Co",
"alternateName": ["Example", "example.com"],
"url": "https://example.com/",
"inLanguage": "en-GB",
"publisher": {
"@id": "https://example.com/#organization"
},
"potentialAction": {
"@type": "SearchAction",
"target": {
"@type": "EntryPoint",
"urlTemplate": "https://example.com/search?q={search_term_string}"
},
"query-input": "required name=search_term_string"
}
}