llms.txt, robots і той HTML, який ШІ-краулери справді читають
ШІ-краулер може процитувати лише те, що здатен завантажити й розібрати. Цей блог постачає майже нуль клієнтського JS, відкритий robots.txt, lastmod на кожен допис у мапі сайту, hreflang, що ніколи не веде на 404, і llms.txt — мапу всієї серії.
Цитованість і схема мають значення лише тоді, коли краулер взагалі отримає байти. Більшість ШІ-краулерів не виконують JavaScript і не повертаються вдруге — вони завантажують один раз, розбирають HTML і йдуть далі. Тож завдання — зробити так, щоб одне просте завантаження повертало все.
Рендерте в HTML; постачайте майже нуль JavaScript
Кожна сторінка — це статичний HTML під час збірки, з двома крихітними вбудованими
скриптами (тема, мова) і нічим для гідратації. Навіть підсвічування синтаксису
відбувається під час збірки — syntaxHighlight: "prism" віддає назви класів, а
не клієнтський скрипт, — тож краулер, що ігнорує JS, усе одно бачить увесь допис,
навігацію та JSON-LD. Нічого важливого не сховано за рендером.
Відчиніть двері в robots.txt, тоді віддайте мапу
robots.txt дозволяє всіх і вказує на абсолютний URL мапи сайту — жодного
ШІ-краулера не виключено окремо:
User-agent: *
Allow: /
Sitemap: https://roman-kocherezhchenko.com/sitemap-index.xml
Далі /llms.txt робить те, чого мапа сайту не може: він впорядковує. Підсумок
у цитаті, примітка «англійські сторінки є канонічними» та написаний від руки
однорядковий опис кожного допису кажуть моделі, про що сайт і які URL варто
читати, — замість змушувати її відновлювати це з сирих маршрутів.
Нехай hreflang і lastmod кажуть правду
Двомовний сайт живе або вмирає на коректності hreflang: одна альтернатива з
404 знецінює весь кластер. Тож сторінка оголошує лише ті мови, які справді має,
обчислені для кожного допису, плюс x-default:
const localeAlternates = [
...availableLocales.map((loc) => ({ hreflang: loc, href: `${origin}/${loc}/${suffix}` })),
{ hreflang: "x-default", href: `${origin}/${xDefaultLocale}/${suffix}` },
];
Мапа сайту так само буквальна. Інтеграція бачить лише URL, тож збірка читає
frontmatter кожного допису й проставляє справжній lastmod із updatedDate ?? pubDate — а сторінки індексу й тегів лишає порожніми, аби не брехати датою
збірки:
serialize(item) {
const lastmod = BLOG_LASTMOD.get(new URL(item.url).pathname);
if (lastmod) item.lastmod = lastmod;
return item;
}
Краулер довіряє тому, що може дешево перевірити: віддайте всю сторінку за одне завантаження, вкажіть йому на URL, що мають значення, і ніколи не оголошуйте той, що віддає 404.
Часті запитання
- Що таке файл llms.txt?
- llms.txt — це файл у звичайному Markdown у корені сайту, що дає ШІ-системам впорядковану мапу найважливіших сторінок з однорядковим описом кожної. llms.txt цього сайту перелічує всю серію risp, репозиторій з кодом, а також сторінки контактів та індексу, і зазначає, що англійські сторінки є канонічними.
- Чи виконують ШІ-краулери JavaScript?
- Здебільшого ні. Більшість ШІ-краулерів завантажують сирий HTML і не виконують надійно клієнтський JavaScript. Цей блог постачає фактично нуль клієнтського JS і рендерить кожну сторінку в статичний HTML під час збірки, тож краулер бачить увесь контент, навігацію та структуровані дані з першого завантаження.
- Як налаштувати hreflang на двомовному сайті?
- Кожна альтернатива hreflang мусить вести на реальну сторінку; єдина ціль із 404 чи відсутнє зворотне посилання знецінює весь кластер. Цей сайт оголошує лише ті мови, які певна сторінка справді має, плюс x-default, тож неперекладений допис ніколи не вказує пошуковику на відсутній переклад.