Atlorium

Сайт «вроде быстрый»: как перевести это ощущение в цифры, за которые платят

Одна и та же страница получает 90 баллов на десктопе и 40 на телефоне, а «поле» и «лаборатория» показывают разное. Объясняем, что именно меряет каждая цифра, какая из них про ваших посетителей, и в каком порядке чинить.

13 минут чтения веб-разработчик · SEO-специалист · владелец сайта · продакт-менеджер

Разговор про скорость сайта почти всегда начинается одинаково. «У нас всё быстро, я проверял» — говорит разработчик, у которого сайт открыт в соседней вкладке с прогретым кэшем, на проводном интернете и на машине за две зарплаты. «У меня грузится вечность» — говорит клиент, открывший тот же адрес с телефона в метро. Оба правы, и спорить им не о чем: они измеряют разное.

Дальше в разговор приходит цифра. Кто-то открывает публичный измеритель, получает «производительность: 38» и приносит это как приговор. Через неделю тот же измеритель показывает 71, хотя не менялось ничего. Доверие к цифре падает, и обсуждение скорости возвращается к ощущениям.

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

Три метрики, которые решают

Core Web Vitals — это набор из трёх показателей, каждый про свой этап знакомства посетителя со страницей. Они специально подобраны так, чтобы не дублировать друг друга.

Метрика Вопрос, на который отвечает Хорошо Плохо
LCP — появление главного содержимого Когда посетитель увидел то, ради чего пришёл: крупную картинку, заголовок, блок текста до 2,5 с больше 4 с
INP — отзывчивость на действия Сколько страница думает, прежде чем отреагировать на нажатие, клик или ввод до 200 мс больше 500 мс
CLS — стабильность вёрстки Насколько содержимое прыгает во время загрузки: успел нажать «отмена», попал в «подтвердить» до 0,1 больше 0,25

К ним обычно прилагаются вспомогательные величины: время до первой отрисовки (когда появилось хоть что-то), общее время блокировки (сколько главный поток был занят и не реагировал), индекс скорости (как быстро заполнялся экран). Они не входят в Core Web Vitals, но полезны при разборе: именно они подсказывают, почему LCP плохой.

Лаборатория против поля: главное различие

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

Лабораторный замер Данные реальных посетителей
Как получается Страница загружается прямо сейчас на стандартизованном устройстве и канале Собирается статистика по посещениям живых людей за прошедший период
Что описывает Один прогон в одинаковых для всех условиях Распределение по всем устройствам, каналам и географии вашей аудитории
Когда обновляется Немедленно: выкатили исправление — увидели результат С задержкой: изменения проявятся, когда наберётся статистика
Для чего годится Сравнение «до и после», поиск причины, регрессионный контроль Оценка реального положения дел и приоритизация: что чинить первым
Когда недоступно Практически никогда: страницу можно загрузить всегда У малопосещаемых страниц — статистики просто не хватает
Есть ли INP Нет: некому нажимать. Вместо него — общее время блокировки Да: живые люди действительно нажимают

Последняя строка — хороший пример того, почему смешивание невозможно в принципе. Отзывчивость на действия нельзя измерить там, где никто не действует. В лаборатории вместо неё смотрят на косвенный признак — сколько времени главный поток был занят. Это разумная замена, но это другая величина, и подставлять одну вместо другой нельзя.

Мобильный и десктопный профили — это два разных ответа

Мобильный замер выполняется на характеристиках среднего телефона: слабее процессор, уже канал, выше задержки. Это не пессимизм ради пессимизма — это медианное устройство реальной аудитории. Отсюда правило, которое экономит много споров: сравнивать мобильную оценку с десктопной бессмысленно.

Разница в 30–40 пунктов между профилями у одной и той же страницы — обычное дело. Тяжёлый JavaScript, который на десктопе разбирается за 200 миллисекунд, на среднем телефоне занимает секунду с лишним, и именно эта секунда решает, останется ли посетитель. Поэтому профили считаются и хранятся раздельно: усреднение здесь скрыло бы ровно ту проблему, ради которой замер и делался.

Код: замер и регрессионный контроль

Один вызов возвращает четыре оценки, лабораторные метрики, полевые данные (если их достаточно) и список узких мест с экономией в миллисекундах по каждому.

Разовый замер и ночной контроль

# Мобильный профиль (по умолчанию)
curl -H "Authorization: Bearer ak_sandbox_demo_mockdata_v1" \
     "https://atlorium.com/api/pagespeed?url=https://example.com"

# Десктопный профиль
curl -H "Authorization: Bearer ak_sandbox_demo_mockdata_v1" \
     "https://atlorium.com/api/pagespeed?url=https://example.com&strategy=desktop"

# Только что выкатили оптимизацию — нужен свежий замер, а не сохранённый
curl -H "Authorization: Bearer ak_sandbox_demo_mockdata_v1" \
     "https://atlorium.com/api/pagespeed?url=https://example.com&forceRefresh=true"

# Пакет: ключевые страницы сайта одним вызовом (до 20 адресов)
curl -X POST \
     -H "Authorization: Bearer ak_sandbox_demo_mockdata_v1" \
     -H "Content-Type: application/json" \
     -d '["https://example.com","https://example.com/catalog","https://example.com/checkout"]' \
     "https://atlorium.com/api/pagespeed/batch?strategy=mobile"
        

import requests

BASE = "https://atlorium.com"
HEADERS = {"Authorization": "Bearer ak_sandbox_demo_mockdata_v1"}

# Таймаут — не меньше 120 секунд. Это внешний замер страницы, а не выборка
# из справочника: браузер действительно загружает сайт, и 10-30 секунд
# на ответ — норма, а не признак неполадки.
TIMEOUT = 150


def audit(url: str, strategy: str = "mobile") -> dict:
    r = requests.get(
        f"{BASE}/api/pagespeed",
        params={"url": url, "strategy": strategy},
        headers=HEADERS,
        timeout=TIMEOUT,
    )
    r.raise_for_status()
    return r.json()


def regression_guard(url: str, floor: int = 60) -> None:
    """Ночной контроль: падение ниже порога — повод разбираться.

    Сравнивается ИМЕННО мобильный профиль: он ближе к медианному
    посетителю и первым показывает деградацию от нового скрипта.
    """
    report = audit(url, "mobile")
    score = report.get("performanceScore")

    if score is None:
        print(f"{url}: замер не выполнен — {report.get('message')}")
        return

    if score < floor:
        print(f"{url}: производительность {score} (порог {floor})")
        # Что чинить — в порядке убывания выигрыша.
        for item in report["opportunities"][:3]:
            print(f"  - {item['title']}: экономия {item['savingsMs']:.0f} мс")
        

using System.Net.Http.Json;

// Таймаут клиента поднят намеренно: замер занимает 10-30 секунд.
HttpClient http = new()
{
    BaseAddress = new Uri("https://atlorium.com"),
    Timeout = TimeSpan.FromSeconds(150),
};
http.DefaultRequestHeaders.Add("Authorization", "Bearer ak_sandbox_demo_mockdata_v1");

SiteReport? report = await http.GetFromJsonAsync<SiteReport>(
    $"/api/pagespeed?url={Uri.EscapeDataString(url)}&strategy=mobile");

// Полевого блока может не быть: у малопосещаемой страницы просто нет статистики.
// Это НЕ ошибка — обрабатываем null как «данных о живых посетителях нет».
string field = report?.FieldData is null
    ? "данных реальных посетителей недостаточно"
    : $"оценка по посетителям: {report.FieldData.OverallRating}";

record SiteFieldData(string Scope, string OverallRating);
record SiteOpportunity(string Title, double SavingsMs);
record SiteReport(
    string Url,
    string FinalUrl,
    int? PerformanceScore,
    int? SeoScore,
    SiteFieldData? FieldData,
    SiteOpportunity[] Opportunities);
        

{
  "url": "https://example.com",
  "finalUrl": "https://example.com/",
  "strategy": "mobile",
  "fetchedAtUtc": "2026-09-01T09:31:07Z",
  "performanceScore": 54,
  "accessibilityScore": 92,
  "bestPracticesScore": 79,
  "seoScore": 96,
  "labMetrics": [
    { "key": "largest-contentful-paint", "title": "Появление главного содержимого",
      "displayValue": "4,1 с", "numericValue": 4120, "unit": "ms", "rating": "poor" },
    { "key": "cumulative-layout-shift", "title": "Сдвиг вёрстки",
      "displayValue": "0,04", "numericValue": 0.04, "rating": "good" }
  ],
  "fieldData": {
    "scope": "page",
    "overallRating": "needs_improvement",
    "metrics": [
      { "key": "LARGEST_CONTENTFUL_PAINT_MS", "percentile": 3200,
        "displayValue": "3,2 с", "rating": "needs_improvement",
        "goodPercent": 61.4, "needsImprovementPercent": 27.1, "poorPercent": 11.5 }
    ]
  },
  "opportunities": [
    { "key": "unused-javascript", "title": "Неиспользуемый JavaScript", "savingsMs": 1840 },
    { "key": "modern-image-formats", "title": "Изображения в современных форматах", "savingsMs": 920 }
  ],
  "elapsedMs": 18430
}
        

Тот же вызов на шести языках (Python, TypeScript, Go, Java, C#, PHP) — в репозитории site-performance-api-client. Примеры запускаются сразу: ключ в них уже стоит демонстрационный.

В каком порядке чинить

Оценка сама по себе — это диагноз без назначений. Практическую ценность даёт список узких мест: он отсортирован по выигрышу, и в нём указано, сколько миллисекунд сэкономит каждое исправление. Это превращает «у нас 54 балла» в план работ.

Начинайте с самого крупного пункта, а не с самого простого. Соблазн сделать сначала лёгкое понятен, но экономия в 40 миллисекунд на фоне полутора секунд неиспользуемого скрипта не изменит ничего — а ощущение работы создаст.

Смотрите, какая метрика плохая, а не только общую оценку. Плохой LCP чинится одними средствами (картинка на первом экране, шрифты, ответ сервера), плохой INP — другими (тяжёлые обработчики, лишние скрипты), плохой CLS — третьими (размеры под изображения и рекламные блоки, зарезервированные заранее). Оптимизация «вообще» распыляет усилия.

Меряйте до и после в одном профиле. Сравнение мобильного замера с десктопным даст «улучшение», которого не было. И не делайте выводов по одному прогону: общая оценка плавает от запуска к запуску даже на неизменной странице.

Проверяйте не только главную. Люди приходят из поиска на карточку товара и статью, а платят на странице оформления заказа. Ключевые страницы стоит держать в ночном прогоне пакетом — заодно поймаете деградацию, приехавшую с чужим скриптом аналитики.

Границы: чего сервис не делает

Не измеряет закрытые страницы. Личный кабинет за формой входа, внутренний портал, страница за корпоративным периметром — замерить их снаружи нельзя. Ответом будет «страница недоступна», и списания за него не будет.

Не заменяет мониторинг доступности. Одиночный замер говорит о скорости в момент замера, а не о том, что сайт лежал ночью двадцать минут. Это разные задачи и разные инструменты.

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

Не показывает историю. Возвращается текущее состояние: свежий лабораторный замер и актуальный срез полевых данных. Динамику за месяцы стройте на своей стороне, сохраняя результаты ночных прогонов, — так вы к тому же увидите ровно те даты, которые вам важны.

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

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

Что такое Core Web Vitals простыми словами?

Три показателя о разном. LCP — через сколько посетитель увидел главное содержимое (хорошо — до 2,5 секунды). INP — насколько быстро страница отвечает на нажатия и клики (хорошо — до 200 миллисекунд). CLS — насколько сильно прыгает вёрстка во время загрузки (хорошо — до 0,1). Одной цифрой они не заменяются: страница может мгновенно показать картинку и при этом десять секунд не реагировать на нажатия.

Почему оценка каждый раз разная, хотя сайт не менялся?

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

В поле метрики хорошие, а в лаборатории плохие. Кому верить?

Обоим — это разные утверждения. Лабораторный замер делается прямо сейчас на стандартизованном «среднем телефоне» и всегда описывает первый визит: он воспроизводим и годится для сравнения «до и после». Полевые данные — статистика по вашим живым посетителям за прошедший период; они часто лучше, потому что аудитория приходит с устройств получше и нередко с прогретым кэшем. Тревожна обратная картина: в лаборатории хорошо, а в поле плохо.

Почему в ответе нет данных о реальных посетителях?

У страницы не хватает трафика, чтобы статистика была представительной. Это нормальный ответ, а не сбой: полевой блок появляется только там, где посещений достаточно. Лабораторный замер при этом выполняется всегда, и для работы «до и после» его хватает.

Чем мобильный замер отличается от десктопного и какой смотреть?

Мобильный выполняется на характеристиках среднего телефона: слабее процессор, уже канал, выше задержки. Разница в 30–40 пунктов у одной и той же страницы — обычное дело, поэтому профили считаются и хранятся раздельно, а сравнивать их между собой бессмысленно. Смотреть стоит тот, с которого приходит ваша аудитория; в большинстве случаев это мобильный.

Сколько ждать ответа и почему так долго?

От 10 до 30 секунд. Это реальная загрузка вашей страницы браузером в стандартизованном окружении, а не выборка из справочника. Практический вывод: клиентский таймаут ставьте не меньше 120 секунд и не вызывайте замер синхронно внутри обработки пользовательского запроса — его место в фоновой задаче или ночном расписании.

Можно ли замерить страницу за формой входа?

Нет. Замер выполняется снаружи, как обычным посетителем, поэтому личный кабинет, внутренний портал и страницы за корпоративным периметром недоступны. Ответом будет «страница недоступна», и списания за него не произойдёт.

Поднимет ли оптимизация скорости сайт в поиске?

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

Сервисы из этой статьи

Аудит сайта

Скорость загрузки и Core Web Vitals: лабораторный прогон, данные реальных посетителей и рекомендации по убыванию выигрыша

Попробовать прямо сейчас — без регистрации

Демо-ключ ak_sandbox_demo_mockdata_v1 — публичный и общий для всех. С ним API отвечает моками: данные правдоподобные, но сгенерированные, и они не меняются от запроса к запросу — на них удобно писать тесты. Настоящие данные приходят с личным ключом.

curl -H "Authorization: Bearer ak_sandbox_demo_mockdata_v1" \
     https://atlorium.com/openapi/speed_ru.json
Полезно? Перешлите коллеге: Telegram VK

Восстанавливаем соединение…

Похоже, связь с сервером ненадолго прервалась. Переподключаемся автоматически — пожалуйста, подождите несколько секунд.

Не удалось переподключиться

Проверьте интернет-соединение. Можно повторить попытку или обновить страницу.

Сессия устарела

Соединение восстановлено, но сессию нужно перезагрузить. Обновите страницу, чтобы продолжить.