Контент рідко старіє різко. Частіше сторінка просто повільно втрачає кліки, CTR, позиції або комерційний сенс. У звітах це не виглядає як аварія: немає 500, немає різкого падіння всього сайту, немає очевидної поломки. Але через кілька місяців команда бачить, що колись сильна стаття вже не приводить трафік, а посадкова сторінка програє новішим матеріалам конкурентів.

Dashboard content refresh queue у Google Sheets з URL, score і рекомендованою дією
Dashboard content refresh queue у Google Sheets з URL, score і рекомендованою дією

Тому content refresh краще вести не “по відчуттю”, а як чергу робіт. Google Sheets тут зручний не тому, що це красивий dashboard, а тому що в одному місці можна зібрати Search Console, GA4 і редакторську логіку: де сторінка просіла, скільки вона важить для бізнесу і що з нею робити.

Які сигнали варто дивитися

Content decay не можна оцінювати тільки за одним показником. Якщо сторінка втратила кліки, але сезон уже закінчився, це не обов'язково проблема. Якщо CTR падає, а позиція не змінилася, можливо, застарів title або SERP став конкурентнішим. Якщо позиція тримається, але конверсій немає, питання може бути не в SEO, а в пропозиції на сторінці.

Для робочого dashboard варто збирати такі поля:

  • clicks_baseline - кліки за попередній стабільний період;
  • clicks_current - кліки за останній період;
  • impressions_delta - чи падає попит або видимість;
  • ctr_delta - чи втрачає сторінка привабливість у видачі;
  • avgpositiondelta - чи просідають позиції;
  • last_updated - коли сторінку реально оновлювали;
  • query_drift - чи змінився набір запитів;
  • conversions або engaged_sessions - чи є бізнес-цінність;
  • priority - наскільки сторінка важлива для команди.

Офіційний Search Console API метод Search Analytics: query дозволяє забирати clicks, impressions, CTR і position по сторінках та запитах. GA4 Data API через runReport допомагає додати engagement або conversions. А SpreadsheetApp закриває запис результатів у Google Sheets.

Структура таблиці

Один рядок у таблиці - одна сторінка, яку команда може оновити, об'єднати, розширити або залишити без змін.

Таблиця content decay queue з кліками, CTR, score і recommended action
Таблиця content decay queue з кліками, CTR, score і recommended action

Практичний набір колонок:

ПолеДля чого потрібне
urlсторінка для аналізу
clusterтема або бізнес-напрям
last_updateдата останнього змістовного оновлення
clicks_baselineнормальний рівень кліків
clicks_currentпоточний рівень кліків
ctr_deltaзміна CTR
position_deltaзміна середньої позиції
query_changeчи змінився набір запитів
business_valuehigh, medium, low
refresh_scoreпріоритет оновлення
recommended_actionrefresh, merge, expand, prune, leave

Важливо не робити колонку recommended_action декоративною. Вона має бути кінцевим результатом аналізу. Якщо сторінка падає, але бізнес-цінності немає, можливо, її краще не переписувати. Якщо сторінка тримає кліки, але query drift показує нові запити, її варто розширити.

Як не плутати сезонність із decay

Не кожне падіння трафіку означає, що контент застарів. Сторінка про сезонну послугу може падати щороку в один і той самий період. Стаття про податкові зміни може різко втратити попит після дедлайну. Новина може нормально відпрацювати свій цикл і більше не потребувати оновлення.

Тому baseline треба рахувати обережно. Для evergreen-сторінок часто достатньо порівняння останніх 28 днів із попередніми 28 днями. Для сезонних сторінок краще порівнювати з аналогічним періодом минулого року. Для сторінок із малим трафіком потрібен мінімальний поріг даних, інакше один-два кліки будуть створювати фальшивий сигнал.

Просте правило: якщо сторінка мала 8 кліків і стала мати 4, це мінус 50%, але не обов'язково задача для редактора. Якщо комерційна сторінка мала 800 кліків і впала до 520, це вже реальний робочий сигнал.

Scoring logic

Добрий dashboard не повинен просто сортувати сторінки за падінням кліків. Він має враховувати кілька шарів: SEO-сигнал, свіжість, бізнес-цінність і рекомендовану дію.

Схема scoring logic для content refresh: Search data, GA4 value, freshness, business priority і action queue
Схема scoring logic для content refresh: Search data, GA4 value, freshness, business priority і action queue

Спрощена логіка може виглядати так:

function scoreContentRefresh() {
  const sheet = SpreadsheetApp.getActive().getSheetByName('Content_Decay');
  const values = sheet.getDataRange().getValues();
  const headers = values.shift();
  const rows = values.map(row => toObject_(headers, row));

  const output = rows.map(row => {
    const baseline = Number(row.clicks_baseline);
    const current = Number(row.clicks_current);
    const ctrDelta = Number(row.ctr_delta);
    const positionDelta = Number(row.position_delta);
    const businessValue = String(row.business_value || '').toLowerCase();
    const lastUpdate = new Date(row.last_update);

    if (!baseline || baseline < 50) {
      return [0, 'leave', 'not enough data'];
    }

    const clicksDrop = (baseline - current) / baseline;
    const monthsOld = (new Date() - lastUpdate) / (1000 * 60 * 60 * 24 * 30);

    let score = 0;
    if (clicksDrop > 0.3) score += 35;
    if (ctrDelta < -1) score += 15;
    if (positionDelta > 2) score += 20;
    if (monthsOld > 9) score += 15;
    if (businessValue === 'high') score += 20;

    let action = 'leave';
    if (score >= 70 && businessValue === 'high') {
      action = 'refresh';
    } else if (score >= 55) {
      action = 'expand';
    } else if (score >= 45 && businessValue === 'low') {
      action = 'merge';
    }

    return [score, action, buildReason_(clicksDrop, ctrDelta, positionDelta, monthsOld)];
  });

  if (output.length) {
    sheet.getRange(2, 10, output.length, 3).setValues(output);
  }
}

function buildReason_(clicksDrop, ctrDelta, positionDelta, monthsOld) {
  return [
    'clicks drop: ' + Math.round(clicksDrop * 100) + '%',
    'ctr delta: ' + ctrDelta,
    'position delta: ' + positionDelta,
    'months old: ' + Math.round(monthsOld)
  ].join('; ');
}

function toObject_(headers, row) {
  return headers.reduce((acc, header, index) => {
    acc[String(header).trim()] = row[index];
    return acc;
  }, {});
}

Це не фінальна модель для всіх сайтів. Це каркас, який змушує команду дивитися не тільки на падіння кліків, а й на те, чи варто сторінку взагалі чіпати.

Що означають різні дії

refresh - сторінка має попит і бізнес-цінність, але дані показують просідання. Тут варто оновити факти, приклади, структуру, title, internal links і блоки, які застаріли.

expand - сторінка не обов'язково слабшає, але з'явилися нові запити або підтеми. Її треба розширити, а не переписувати з нуля.

merge - є кілька слабких сторінок на близьку тему. Краще зібрати один сильний матеріал і налаштувати перенаправлення, ніж підтримувати кілька напівживих URL.

prune - сторінка не має трафіку, цінності й актуальності. Іноді видалення або закриття від індексації корисніше за косметичне оновлення.

leave - даних недостатньо або сторінка працює нормально. Це теж рішення. Dashboard має зменшувати зайву роботу, а не створювати її.

Rocket-підхід

Сильна content refresh система має відповідати на три питання.

Перше: де є реальний сигнал, а не статистичний шум. Для цього потрібні baseline, пороги й мінімальний обсяг даних.

Друге: де є бізнес-сенс. Сторінка з невеликим трафіком може бути важливішою за популярну статтю, якщо вона приводить заявки або підтримує продажі.

Третє: яка дія потрібна. Не кожну сторінку треба переписувати. Одну варто освіжити, другу розширити, третю об'єднати, четверту залишити.

Content refresh має бути чергою рішень, а не реакцією на відчуття. Коли в таблиці видно URL, score, причину і рекомендовану дію, команда перестає сперечатися про “застаріло чи ні” і починає планувати конкретну редакційну роботу.