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, тож неперекладений допис ніколи не вказує пошуковику на відсутній переклад.

← Усі дописи