GEO на Tilda: llms.txt, JSON-LD и индексация

GEO на Tilda: llms.txt, JSON-LD и индексация на конструкторе
SEO/GEO

У владельца сайта на Tilda нет доступа к корню домена, поэтому llms.txt обычным способом туда не положить. Скрипты из общих настроек страницы конструктор фильтрует, и блок с разметкой JSON-LD до опубликованной страницы не доходит. Оба ограничения обходятся: файл отдает обработчик на стороне Cloudflare, а разметка уходит в блок с собственным HTML внизу страницы.

Ниже разбор на сайте hitz.agency, май 2026. Файл открывается по своему адресу и отдает чистый markdown. На пяти страницах стоит 19 блоков разметки. В 30 вопросах FAQ формулировки совпали с видимым текстом дословно, предупреждений в Search Console нет. От запроса на индексацию главной до подтверждения, что адрес в индексе, прошло 30 минут.

Текст писался для Хабра и был снят модератором за упоминание агентства. Правила площадки, вопросов нет. Разбор от этого хуже не стал, поэтому выходит здесь. Что такое GEO и чем оно отличается от SEO, разобрано в отдельной статье, здесь только техническая часть на конструкторе.

Чего конструктор не разрешит

Ограничений три, и они бьют по разным задачам.

  • Корень домена закрыт. Доступа по FTP нет, файловой системы у владельца сайта тоже нет. Вместе с llms.txt отпадают security.txt, ads.txt и любой другой файл, который по стандарту лежит по адресу вида домен, слеш, имя файла.
  • Общей настройки head на весь сайт нет. Вписанное в настройки одной страницы на соседние не распространяется, поэтому набор разметки приходится повторять руками везде.
  • Скрипты из настроек страницы фильтруются выборочно. Счетчики аналитики и пиксели проходят, свой блок script с типом application/ld+json пропадает. Проверяется за минуту: вставьте код, сохраните, откройте исходный код опубликованной страницы и поищите там свою разметку. Ее не будет.
  • Теги meta и link из тех же настроек уходят на страницу без вопросов.
  • Файлы robots.txt и sitemap.xml генерируются автоматически. Править их получится только через панель и не во всем.

Так задумано. Конструктор собран под маркетолога, который делает страницы мышкой, а не под техническую доводку сайта. Это свойство продукта, а не ошибка: за скорость сборки платят закрытым доступом к серверу. Tilda мы выбирали сознательно и работать на ней продолжаем.

Сам llms.txt нужен для того, чтобы модель в момент запроса не разбирала меню, баннеры и виджеты, а взяла готовый список главных страниц с описаниями. Зачем нужен этот файл и кто его читает, подробно разобрано на сайте агентства. Здесь речь про другое: как поднять его там, где корня нет.

Что закрыто Чем обошли Нет доступа к корню домена llms.txt положить некуда Обработчик Cloudflare Worker отвечает на адрес до сайта Нет общей настройки head настройки страницы не наследуются Набор разметки на каждой странице 19 блоков на 5 страницах Свой скрипт вырезается JSON-LD из настроек не доходит Блок с HTML в теле страницы T123 принимает скрипты

llms.txt без доступа к корню: Cloudflare Worker

Условие одно: домен обслуживается на DNS Cloudflare. Тариф подойдет любой, бесплатного хватает.

Cloudflare Worker - небольшой обработчик, который выполняется на серверах Cloudflare раньше, чем запрос дойдет до сайта. Для нашей задачи он делает одну вещь: отвечает по адресу со слешем llms.txt и отдает текст. Содержимое файла лежит внутри кода как обычная строка.

export default {
  async fetch() {
    const body = [
      "# HITZ Agency",
      "",
      "> GEO-агентство в Центральной Азии. Выводим бренды в ответы",
      "> ChatGPT, Perplexity, Gemini и AI Overviews.",
      "",
      "## Основные страницы",
      "",
      "- [Главная](https://hitz.agency/): услуги, подход, форматы работы",
      "- [Блог](https://hitz.agency/blog): разборы по видимости в AI-выдаче",
      "",
      "## Материалы",
      "",
      "- [Что такое llms.txt](https://hitz.agency/blog/chto-takoe-llms-txt):",
      "  спецификация файла, статусы платформ, инструкции по движкам",
      "",
      "## Контакты",
      "",
      "- Telegram: https://t.me/marataxanov",
      ""
    ].join("\n");

    return new Response(body, {
      headers: {
        "content-type": "text/plain; charset=utf-8",
        "cache-control": "public, max-age=3600"
      }
    });
  }
};

Дальше обработчик привязывается к маршруту в настройках Worker, поле Routes: адрес домена со слешем llms.txt. С этого момента запрос по адресу файла до сайта не доходит, на него отвечает Cloudflare.

Там же выставляется режим отказа, и здесь важен выбор. Мы поставили Fail closed. Если обработчик по какой-то причине не отработает, Cloudflare вернет ошибку и запрос дальше не пропустит. Второй режим, Fail open, отправил бы запрос на сайт, а конструктор ответил бы своей страницей 404 или редиректом на главную. Краулер по адресу файла получил бы HTML вместо markdown, и это худший из возможных ответов: пустая ошибка честнее, чем страница с меню и баннером под видом машиночитаемого файла.

Проверяли двумя способами. Первый - запрос через curl.

curl -i https://hitz.agency/llms.txt

HTTP/2 200
content-type: text/plain; charset=utf-8
cache-control: public, max-age=3600

# HITZ Agency

> GEO-агентство в Центральной Азии. Выводим бренды в ответы
> ChatGPT, Perplexity, Gemini и AI Overviews.

В ответе смотрим на три вещи: код 200, заголовок content-type с типом text/plain, начало markdown. Второй способ проще и не требует терминала: откройте адрес в окне инкогнито. В браузере должен появиться текст без оформления, без шапки сайта и без меню. Если видите привычную страницу сайта, маршрут не сработал.

Кеширование на час поставили осознанно. Файл меняется редко, а каждый повторный запрос при таком заголовке отдается из кеша Cloudflare, минуя обработчик. Если правите содержимое и хотите увидеть новую версию сразу, сбросьте кеш по адресу в панели или проверяйте с параметром, который его обходит.

Расход на бесплатном тарифе Workers ограничен сотней тысяч запросов в сутки. На рабочем сайте до этой границы далеко: у нас счет идет на десятки запросов в сутки, то есть меньше тысячной доли лимита.

Способ подходит не только Tilda. Wix, Squarespace, чужая система без доступа к серверу, сайт, доставшийся по наследству вместе с забытыми паролями от панели, - везде, где корень закрыт, обработчик на стороне сети решает задачу за полчаса. Условие ровно одно: домен на DNS Cloudflare.

Что кладут внутрь. Не копию карты сайта, а отбор: 20-50 приоритетных страниц с короткими описаниями, сгруппированных по разделам. Карта сайта перечисляет адреса подряд и решает другую задачу. Пишется файл в редакторе простого текста, где нет автозамены кавычек и скрытого форматирования.

Обслуживать его придется руками. Вышел новый опорный материал - в списке появляется строка со ссылкой и описанием. Иначе через полгода файл описывает сайт, которого уже нет.

Ограничение подхода назову прямо: содержимое лежит внутри кода обработчика. Каждая правка списка страниц - это правка кода и повторная публикация Worker. Автоматической связи с сайтом нет, и для блога, где материалы выходят каждую неделю, порядок придется придумывать отдельно.

Краулер просит /llms.txt Cloudflare маршрут совпал, работает обработчик Ответ 200, markdown content-type: text/plain Обработчик не отработал Fail closed: ошибка, дальше стоп Без режима отказа: сайт отдаст 404

JSON-LD, когда скрипты вырезаются из настроек страницы

По документации Schema.org разметка размещается и в head, и в теле страницы: поисковые системы и модели читают оба варианта одинаково. Отсюда и выход из положения, когда head закрыт.

В Tilda для этого есть блок T123 - собственный HTML внутри страницы. Он принимает содержимое как есть, включая скрипты, и после публикации разметка видна в исходном коде.

Ставится блок в самый низ страницы. Скрипт с разметкой ничего не рисует, высота у него нулевая, верстка не сдвигается ни на пиксель. Один блок вмещает несколько объектов сразу, поэтому плодить их по числу типов разметки не нужно: у нас на статье блога четыре объекта стоят в одном. После публикации откройте исходный код страницы и найдите там свой код - на этом проверка вставки заканчивается.

Что получилось. Управление ушло на уровень страницы: у каждой свой набор блоков, ничего лишнего не наследуется. Что потерялось: общего места для разметки по-прежнему нет, поэтому Organization приходится дублировать везде. На пяти страницах вышло 19 блоков, и каждый ставился руками.

Раскладка по типам страниц получилась такая:

  • Главная: Organization, WebSite с указанием издателя, FAQPage на четыре вопроса.
  • Статья блога: Organization повторно, Article с издателем и автором, FAQPage, BreadcrumbList из трех уровней.

Отдельно про поле автора. В нем стоит Person с именем и адресом личного сайта, и это не формальность. Статья на сайте агентства ссылается на личный домен автора, личный домен ссылается обратно на агентство. Две сущности подтверждают друг друга, и модели получают связку вместо двух безымянных описаний. Для небольшого бренда, у которого нет статьи в Википедии и упоминаний в отраслевой прессе, такая связка иногда единственное, за что можно зацепиться.

Какие типы разметки ставить, что они дают и чего от них ждать не стоит, разобрано в статье про разметку для AI.

Связи через @id: почему набор блоков без них не работает

Несколько блоков разметки на одной странице без явных связей читаются как отдельные описания. Organization сам по себе, WebSite сам по себе, Article сам по себе. Ни поисковая система, ни модель не догадаются, что речь об одной организации: догадываться им не положено, они читают то, что написано.

Решение простое и стоит одну строку. Главной сущности присваивается идентификатор @id, обычно адрес страницы с якорем, а остальные блоки ссылаются на него.

{
  "@context": "https://schema.org",
  "@type": "Organization",
  "@id": "https://hitz.agency/#organization",
  "name": "HITZ Agency",
  "url": "https://hitz.agency/",
  "description": "GEO-агентство в Центральной Азии",
  "sameAs": [
    "https://t.me/marataxanov",
    "https://www.linkedin.com/in/marataksanov/"
  ]
}

Блок сайта после этого ссылается на идентификатор вместо того, чтобы описывать организацию заново.

{
  "@context": "https://schema.org",
  "@type": "WebSite",
  "@id": "https://hitz.agency/#website",
  "url": "https://hitz.agency/",
  "name": "HITZ Agency",
  "publisher": { "@id": "https://hitz.agency/#organization" }
}

Ради предпоследней строки все и затевалось. Поле publisher ссылается на идентификатор организации, и два блока собираются в один граф. Уберите ее - и на странице останутся два независимых описания, между которыми нет ничего.

Со статьей порядок тот же: издатель через идентификатор, автор отдельным объектом.

{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "Что такое llms.txt",
  "datePublished": "2026-05-14",
  "dateModified": "2026-05-14",
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://hitz.agency/blog/chto-takoe-llms-txt"
  },
  "publisher": { "@id": "https://hitz.agency/#organization" },
  "author": {
    "@type": "Person",
    "name": "Марат Аксанов",
    "url": "https://aksanov.digital/"
  }
}

Рядом с @id работает поле sameAs, и задача у него похожая, только связывает оно не блоки внутри страницы, а профили бренда снаружи. Без sameAs сайт, страница в LinkedIn и канал в Telegram остаются тремя разными организациями с похожими названиями. С ним модель собирает их в одну сущность.

Собрались связи или нет, видно в валидаторе Schema Markup Validator. Он показывает граф целиком: вложенные объекты видны внутри родительских, а блок без связей стоит отдельным деревом. Проверка занимает минуту и снимает главный вопрос: код может быть валидным и при этом рассыпаться на части.

Связи через @id Без связей Organization @id: /#organization WebSite publisher Article publisher, author BreadcrumbList адрес страницы Organization WebSite Article Три описания на одной странице, между ними пусто

FAQPage один в один с видимым текстом

Правило здесь жесткое: вопросы в разметке совпадают с вопросами на странице дословно. Стоит в блоке на странице «Что такое GEO?», а в разметке «Что обозначает GEO?» - Search Console пометит это как несоответствие, и расширенные результаты могут не появиться вовсе.

Прием, который снимает проблему целиком: копировать вопросы из текста в разметку, а не сочинять их заново. Разница в одном слове стоит предупреждения в отчете.

На нашем сайте вышло 30 вопросов на четырех статьях. Все 30 перенесены копированием, отчет по расширенным результатам чистый.

За частным правилом стоит общее. Разметка описывает то, что на странице есть. Описанное в коде, но отсутствующее в тексте, читается как попытка выдать желаемое, а такие вещи чинят не отчеты, а редактор. Зачем FAQ-разметка нужна сейчас, когда Google свернул показ расширенных результатов по ней, разобрано в статье про типы разметки.

robots.txt на конструкторе и остаточные запреты

Файл генерируется автоматически, руками его не переписать. Правки идут через панель: Сайт, Настройки, раздел SEO.

Типовая находка ждала нас там же, где ждет большинство. В файле висели два запрета, оставшихся от прежних настроек: две статьи блога когда-то стояли черновиками со скрытым адресом, черновиками быть перестали, а строки в robots.txt остались. Ни одна панель об этом не сообщает.

Отсюда правило, которое стоит минуты: после публикации откройте свой robots.txt глазами и прочитайте его целиком. Панель показывает то, что вы в нее ввели, а файл отдает то, что накопилось.

Рабочий вид файла короткий: разрешение для основного набора краулеров и адрес карты сайта.

User-agent: *
Allow: /

User-agent: GPTBot
Allow: /

User-agent: ChatGPT-User
Allow: /

User-agent: ClaudeBot
Allow: /

User-agent: PerplexityBot
Allow: /

User-agent: Google-Extended
Allow: /

Sitemap: https://hitz.agency/sitemap.xml

Карта сайта собирается по тому же принципу: конструктор складывает в нее опубликованные страницы сам. Перед отправкой в Search Console мы открыли ее и прочитали список адресов. Смотреть надо на две вещи: попали ли туда все страницы, которые должны попасть, и не уехали ли в карту служебные адреса вроде страницы благодарности после формы. Лишний адрес в карте - это приглашение краулеру потратить время впустую.

По данным Ahrefs, около 6% сайтов из выборки в 140 млн закрывают GPTBot, краулер OpenAI. Владельцы в большинстве своем такого решения не принимали: запрет достался вместе с шаблоном или остался от прежнего подрядчика. Сайты на конструкторах в эту выборку попадают охотно.

Закрыть всех краулеров разом - не защита содержимого, а отказ от канала. Содержимое от этого никуда не денется, а бренд пропадет из ответов там, где его ищут. Полный список AI-краулеров и задачи каждого собраны в отдельном разборе.

Подвох Cloudflare: блокировка обучающих ботов

Раздел для тех, у кого все настроено, а результата нет.

В Cloudflare есть отдельная настройка, которая блокирует обучающих AI-краулеров. Включенная в режим блокировки, она отрезает их на своей стороне, и написанное в robots.txt в этот момент никого не интересует: до robots.txt запрос не доходит.

Выглядит ситуация обманчиво спокойно. Файл robots.txt открыт, валидатор разметки зеленый, карта сайта отдается, а в логах по AI-краулерам тишина. На поиск причины ушел час, и весь этот час мы искали ошибку в файлах, которые были в порядке.

Похожая функция в Cloudflare включается по умолчанию и сама дописывает в robots.txt сигнал не использовать содержимое сайта для обучения моделей. Сайты, переехавшие на Cloudflare, оказываются закрыты для части краулеров, а владельцы об этом не знают: настройку никто не трогал, она такая с самого начала.

Проверять надо и firewall, и сервер. Трафик AI-краулеров иногда попадает под подозрительный и режется правилами защиты, которые ставились от совсем других гостей.

Итог раздела короткий. У запрета три возможных места: robots.txt, edge-уровень Cloudflare, firewall или настройки сервера. Проверять стоит в этом порядке, от простого к тому, куда лезут в последнюю очередь.

Отдельно держите в уме, что обучение и поиск в момент запроса - разные задачи краулеров. Запретить обучение и оставить доступ для ответов возможно, это настраивается по именам ботов. Разбор задач и имен - в статье про AI-краулеров.

AI-краулер robots.txt старые запреты Cloudflare блокировка ботов Firewall и сервер Открыть файл глазами, прочитать целиком Настройка AI-ботов в панели домена Правила защиты, логи по именам ботов Зеленый валидатор проверяет только код разметки. Запрет срабатывает вне страницы.

Search Console: доменный ресурс вместо ресурса на http

Симптом такой. Карта сайта добавлена, а Search Console сообщает, что получить ее не удалось. Сама карта при этом открывается в браузере, отдает код 200 и валидный XML.

Причина лежит в истории проекта. Если сайт когда-то работал по http и тогда же был добавлен в Search Console, там до сих пор зарегистрирован ресурс на http. Карта отдается по https и к такому ресурсу не привязывается. Формально все верно, для Search Console это два разных сайта.

Лечится добавлением доменного ресурса. Он покрывает сразу все варианты адреса: http, https, с поддоменом www и без. Подтверждается записью TXT в DNS, на Cloudflare она добавляется в панели за пару минут.

Порядок действий получился такой:

1. Добавьте доменный ресурс и подтвердите его записью TXT. 2. Отправьте карту сайта уже в новый ресурс. 3. Запросите переобход главной и опорных страниц через проверку URL. 4. Старый ресурс удалите после того, как новый начнет собирать данные.

От запроса на индексацию главной до подтверждения, что адрес в индексе, прошло 30 минут. Оговорюсь сразу: это свежий сайт с открытым robots.txt, готовой разметкой и работающим llms.txt, и цифра описывает один случай на одном домене. Обещать такие сроки нельзя, ждать их по умолчанию тоже.

Запросы на переобход лимитированы, порядка 10-12 в сутки на ресурс. Отсюда очередность: сначала главная и опорные страницы, остальное уходит следующими днями или доходит само.

Яндекс Вебмастер подключается тем же порядком: подтверждение прав, карта сайта, запрос обхода по важным адресам.

Было Стало Ресурс в Search Console: http Карта сайта отдается по https Привязки нет: «карта не получена» Доменный ресурс подтвержден записью TXT http https www без www Карта сайта принята, переобход запрошен

Что осталось незакрытым

Разбор был бы неполным без списка того, что к моменту публикации не доделано.

Перелинковка с главной. У главной страницы нашлась ровно одна внутренняя ссылка, и вела она на саму себя. Материалы блога с главной не видны, значит и вес на них не идет, и краулер добирается до них дольше. Нужен блок с материалами, и это ближайшая задача.

FAQ на главной. Сейчас там четыре вопроса, а хочется семь-девять: больше вопросов - больше фрагментов, которые модель может забрать в ответ. Кандидаты понятны: стоимость работ, география, отличие от классического SEO.

Старые адреса. Прежнее позиционирование сайта оставило после себя страницы, которые сейчас отдают 404, но еще держатся в индексе. Запрос на удаление отправлен, параллельно они выпадают сами.

Замер видимости. Базовый срез снят 5 мая: 15 запросов, пять систем, фиксация того, кого называют в ответах и на кого ссылаются. Повторный замер идет по тому же списку, иначе сравнивать нечего. Пока техническая часть только встала на место, и обсуждать по ней динамику рано: между открытым доступом для краулера и упоминанием в ответе лежит несколько недель и содержимое сайта.

И оговорка ко всей статье. Техническая часть - условие попадания в ответы, а не причина. Без нее не работает ничего: краулер не дойдет, разметка рассыпется, файл вернет страницу 404 вместо текста. С ней тоже ничего не работает само по себе, потому что дальше нужен материал, который стоит цитировать. Первое делается за день, второе - месяцами.

Коротко

  • Три ограничения конструктора: закрытый корень домена, отсутствие общей настройки head, фильтрация своих скриптов из настроек страницы.
  • Файл llms.txt отдает Cloudflare Worker, привязанный к маршруту со слешем llms.txt. Режим отказа - Fail closed, иначе по адресу файла краулер получит страницу 404.
  • JSON-LD уходит в блок T123 внизу страницы: Schema.org разрешает и head, и body. Набор повторяется на каждой странице, у нас вышло 19 блоков на пяти.
  • Блоки связываются через @id, профили бренда - через sameAs. Без связей на странице лежат отдельные описания.
  • Краулер теряется в трех местах: robots.txt, edge-уровень Cloudflare, firewall или сервер. Проверять стоит все три.
  • Search Console: доменный ресурс покрывает все варианты адреса, ресурс на http карту по https не примет.

Частые вопросы

Как положить llms.txt на Tilda, если нет доступа к корню сайта?

Через обработчик на стороне Cloudflare. Домен переводится на DNS Cloudflare, создается Worker, который отвечает текстом по адресу со слешем llms.txt, и привязывается к маршруту. Содержимое файла хранится внутри кода обработчика. Запрос до сайта не доходит, конструктор о нем не знает. На бесплатном тарифе способ обходится в ноль, настройка занимает около получаса.

Почему Tilda вырезает JSON-LD из настроек страницы?

Конструктор фильтрует скрипты, вставленные через настройки страницы: счетчики аналитики и пиксели проходят, произвольный блок script с типом application/ld+json - нет. Проверяется вставкой и просмотром исходного кода опубликованной страницы. Обход простой: разметка ставится блоком T123 в теле страницы, куда HTML попадает без изменений. Schema.org разрешает оба размещения.

Где на Tilda правится robots.txt?

Файл генерируется автоматически, править его получится только через панель: Сайт, Настройки, раздел SEO. Отредактировать его как обычный файл не выйдет. После правок откройте адрес robots.txt в браузере и прочитайте файл целиком: там нередко остаются запреты от старых черновиков и скрытых страниц, о которых панель не напоминает.

Почему AI-боты не заходят на сайт, хотя robots.txt открыт?

У запрета есть еще два места. Первое - настройка блокировки AI-краулеров в Cloudflare: она работает раньше robots.txt и отсекает ботов на своей стороне. Второе - правила firewall или сервера, где трафик ботов попадает под подозрительный. Проверять стоит по очереди: robots.txt, панель Cloudflare, логи по именам ботов.

Search Console пишет, что карта сайта не получена. Что делать?

Проверьте, какой ресурс добавлен. Если это ресурс на http, а карта отдается по https, привязки не будет, и отчет так и останется пустым. Добавьте доменный ресурс: он покрывает http, https, адрес с www и без. Подтверждение идет записью TXT в DNS. После этого отправьте карту заново и запросите переобход главной.

Работает ли этот способ на Wix и других конструкторах?

Да, условие одно: домен обслуживается на DNS Cloudflare. Обработчик отвечает на адрес раньше, чем запрос уходит на сайт, поэтому система, которая стоит за доменом, роли не играет. Способ подходит для Wix, Squarespace, самописных сайтов без доступа к серверу и любых проектов, где корень закрыт. Разметка через блок с HTML требует, чтобы такой блок в конструкторе был.

Об авторе

Марат Аксанов, performance‑маркетолог. 12 лет в маркетинге и медиа.

Сертифицированный специалист DV360, Google Ads и Google Analytics.

Заказать аудит вашего проекта или консультацию:

Марат Аксанов, performance-маркетолог