SEO
Make every page easy to find and easy to use. Give each one its own title and description, describe what it's about with structured data, keep its headings in order and make it load fast. Give every document its own title and description fields, and bind them in the <head> of its component.
Do
- Write a title and description for every page, matching what's on it.
- Add structured data as microdata on the visible markup, so the data and the text never drift apart.
- Use one
<h1>per page and don't skip heading levels below it. - Give the largest image at the top of the page
loading="eager"andfetchpriority="high". - Answer the question a heading asks in the first sentence below it, so AI assistants can quote it.
Don't
- Don't hardcode the title or description in a component.
- Don't use JSON-LD for data that's already shown on the page.
FAQ
Do I need to write a sitemap?
No. Once the project has its own domain, publishing generates /sitemap.xml and /robots.txt. If you prefer to write your own, you can overwrite in /assets/.
Do I need to lazy load images?
No. When the site is published, the first <img> on each page loads with high priority and every other one gets loading="lazy" and decoding="async" automatically.
When do I use JSON-LD? Only for data that isn't shown on the page.
Which structured data should I add?
Whatever the page shows that has a schema.org type: a FAQPage for questions and answers, a Product with its Offer for something you sell, a Review for a testimonial, an Article for a blog post, an Organization for the site itself.
What about GEO and AEO? Generative and answer engine optimization (getting cited by ChatGPT, Perplexity or Google's AI answers) mostly comes down to the same things: static HTML that crawlers read without running JavaScript, structured data, and clear, factual answers near the top of each section. Concrete numbers, names and dates get quoted more than vague claims.
Example
Page, Lesson and Product each get a title and a description field.
# /schemas/Page.yml
fields:
title: { type: string, max: 60, default: "" }
description: { type: string, max: 155, default: "" }
<!-- /components/Page.html -->
<head>
<title x-bind="title"></title>
<meta name="description" x-bind:content="description">
</head>
A Faq section marks up its questions as a FAQPage.
<!-- /components/Faq.html -->
<section itemscope itemtype="https://schema.org/FAQPage">
<div x-for="questions" itemprop="mainEntity" itemscope itemtype="https://schema.org/Question">
<h3 itemprop="name" x-bind="question"></h3>
<div itemprop="acceptedAnswer" itemscope itemtype="https://schema.org/Answer">
<p itemprop="text" x-bind="answer"></p>
</div>
</div>
</section>