Blazor — это четыре разных способа размещения под одним именем, и сниппет идёт в разный файл в каждом. Правило под ними одно: он принадлежит той оболочке, которая переживает навигацию, и никогда не странице.
Этот сайт сделан на Blazor, и Skomi измеряет его именно так.
Сначала возьмите сниппет в своей панели:
<script src="https://t.skomi.com/s/YOUR-SITE-ID.js" defer></script>
Куда он идёт
| Ваш проект | Файл | Место в нём |
|---|---|---|
| Blazor Web App (.NET 8+) | Components/App.razor | В <body>, после <Routes /> |
| Blazor WebAssembly, отдельный | wwwroot/index.html | В <body>, перед скриптом фреймворка |
| Blazor Server (.NET 6/7) | Pages/_Host.cshtml или Pages/_Layout.cshtml | В <body> |
| MAUI Blazor Hybrid | не применимо | Не сюда: это приложение, смотрите установку на MAUI |
Для Blazor Web App это выглядит так:
<body>
<Routes />
<script src="https://t.skomi.com/s/YOUR-SITE-ID.js" defer></script>
<script src="_framework/blazor.web.js"></script>
</body>
Почему не в макете и не на странице
⚠ Скрипт, вставленный расширенной навигацией, не выполняется. Blazor патчит DOM, а не перезагружает документ, и тег <script>, пришедший в составе этого патча, не запускается. Поэтому сниппет, положенный в MainLayout.razor или в компонент страницы, работает при первой загрузке, тихо мёртв после первого внутреннего перехода и всё это время выглядит установленным.
App.razor находится вне всего, что Blazor заменяет. Тег загружается один раз и остаётся загруженным.
Переходы считаются за вас
Происходят две разные вещи в зависимости от того, везёте ли вы среду выполнения Blazor, и обе уже обработаны.
С blazor.web.js внутренние ссылки используют расширенную навигацию: документ выживает, а адрес меняется через history.pushState. Скрипт Skomi оборачивает pushState и replaceState и слушает popstate, так что каждое из этого — просмотр страницы. Подписываться не на что, вызывать при переходе нечего.
Без неё — приложение Blazor, отрисованное статически и без интерактивности, не везёт среду выполнения вовсе, поэтому каждая ссылка это обычная загрузка страницы и считается как на любом другом сайте. Этот сайт — как раз такой случай.
Знать, какой у вас случай, не обязательно: тот же тег в том же месте верен для обоих.
⚠ Переход, не меняющий адрес, не считается, ни в одном из режимов. Вкладки, раскрывающиеся блоки и смена фильтров без параметров в адресе — это взаимодействия, а не просмотры страниц. Если вы хотите их измерять, шлите событие.
Интерактивные режимы отрисовки здесь ничего не меняют
InteractiveServer, InteractiveWebAssembly и InteractiveAuto решают, где выполняются ваши компоненты, а не как страница доставляется в браузер. Сниппет стоит выше всего этого в App.razor и ведёт себя одинаково при каждом. Режимы отрисовки на уровне компонентов тоже не имеют значения: документ один, и скрипт один.
Если ничего не приходит
- Тег в
App.razor, а не в макете? Смотрите предупреждение выше; ради этой ошибки эта страница и существует. - Он внутри
<body>? В<head>он тоже работает, но не путайтесь под ногами у<HeadOutlet />: этот вывод предназначен для содержимого, которое дают компоненты, а трекер таковым не является. dotnet watchи закешированный документ. Расширенная навигация и горячая перезагрузка могут оставить вас смотрящим на страницу, собранную до добавления тега. Обновите один раз с очисткой кеша.- Localhost не считается. Выложите или проверяйте на настоящем имени хоста.
Что делает сниппет после загрузки, смотрите в установке сниппета, а измерение приложения, если измеряете вы программу, которую люди устанавливают, а не сайт, на который они заходят.