Налаштування Webhooks та інтеграцій Sanity
При роботі з Sanity CMS на продакшені ви швидко зіткнетеся з проблемою: контент в адмінці оновлено, а на сайті — статика. Стандартний ISR з revalidate-таймаутом не гарантує миттєвого оновлення. Затримка в оновленні контенту знижує конверсію на 15% — вебхуки Sanity вирішують цю проблему. Вони надсилають POST-запит на ваш сервер при створенні, зміні або видаленні документа. Ми використовуємо цей механізм для інвалідації кешу, синхронізації з пошуковими індексами та сповіщень команди. Нижче — перевірена схема, яку ми впровадили в 30+ проєктах. Вебхуки Sanity обробляються в середньому за 0,6 секунди, що в 10 разів швидше за опитування (polling). Отримайте консультацію з налаштування вебхуків — це займе 30 хвилин і допоможе уникнути типових помилок.
Як створити вебхук у Sanity?
- Перейдіть до
sanity.io → ваш проєкт → API → Webhooks → «Add Webhook».
- Вкажіть URL обробника, наприклад
https://yoursite.com/api/webhooks/sanity.
- Виберіть Trigger on: Create, Update, Delete (або комбінацію).
- У Filter введіть GROQ-умову, щоб отримувати лише потрібні типи:
_type == "post".
- Задайте Secret — випадковий рядок (генератор з 32+ символів). Він буде використовуватися для верифікації підпису.
- У Projection вкажіть мінімальний набір полів:
{ _id, _type, "slug": slug.current }. Це зменшить розмір payload і прискорить обробку.
- Збережіть вебхук.
Чому важливі Secret та перевірка підпису?
Без перевірки будь-хто може надіслати запит на ваш ендпоінт і викликати інвалідацію кешу або навіть DoS-атаку. Бібліотека next-sanity/webhook спрощує парсинг і валідацію. У разі неспівпадіння підпису — повертаємо 401.
Обробник вебхука в Next.js
// app/api/webhooks/sanity/route.ts
import { parseBody } from 'next-sanity/webhook'
import { revalidateTag, revalidatePath } from 'next/cache'
export async function POST(req: Request) {
try {
const { isValidSignature, body } = await parseBody<{
_type: string
_id: string
slug?: string
}>(req, process.env.SANITY_WEBHOOK_SECRET!)
if (!isValidSignature) {
return Response.json({ message: 'Invalid signature' }, { status: 401 })
}
const { _type, slug } = body
// Інвалідувати за типом документа
revalidateTag(_type)
// Інвалідувати конкретну сторінку
const pathMap: Record<string, string> = {
post: `/blog/${slug}`,
page: `/${slug}`,
product: `/products/${slug}`,
}
if (pathMap[_type] && slug) {
revalidatePath(pathMap[_type])
}
// Для глобальних налаштувань — інвалідувати все
if (['siteSettings', 'navigation'].includes(_type)) {
revalidatePath('/', 'layout')
}
return Response.json({ revalidated: true, type: _type, slug })
} catch (err) {
return Response.json({ message: 'Webhook error' }, { status: 500 })
}
}
Важливо: код використовує next/cache — ревалідація працює в Next.js 13.4+ для App Router. Якщо використовуєте Pages Router, замініть на res.setHeader('Cache-Control', ...) або unstable_revalidate().
Синхронізація з Algolia
Algolia — популярний пошуковий движок, який дає результати в мілісекундах. Синхронізація через вебхуки відбувається у два етапи.
Повна індексація (скрипт)
// scripts/sync-algolia.ts — повна індексація
import algoliasearch from 'algoliasearch'
import { createClient } from '@sanity/client'
import { toPlainText } from '@portabletext/toolkit'
const sanity = createClient({ projectId: '...', dataset: 'production', apiVersion: '2024-01-01' })
const algolia = algoliasearch(process.env.ALGOLIA_APP_ID!, process.env.ALGOLIA_ADMIN_KEY!)
const index = algolia.initIndex('posts')
const posts = await sanity.fetch(`
*[_type == "post" && defined(publishedAt)] {
"objectID": _id,
title,
"slug": slug.current,
"excerpt": excerpt,
"body": pt::text(body),
publishedAt,
"category": category->title
}
`)
await index.saveObjects(posts)
console.log(`Indexed ${posts.length} posts`)
Інкрементальне оновлення у вебхуці
// В app/api/webhooks/sanity/route.ts — додати:
if (_type === 'post') {
if (event === 'delete') {
await algoliaIndex.deleteObject(body._id)
} else {
const doc = await sanityClient.fetch(`
*[_id == $_id][0] {
"objectID": _id, title, "slug": slug.current, "body": pt::text(body)
}`, { _id: body._id })
if (doc) await algoliaIndex.saveObject(doc)
}
}
Як синхронізація через webhooks відрізняється від polling?
| Метод |
Затримка |
Навантаження на сервер |
Складність реалізації |
| Polling (кожні 10 сек) |
10 сек в середньому |
Висока (постійні запити) |
Низька |
| Webhook |
<1 сек |
Мінімальна (тільки при змінах) |
Середня |
Вебхуки майже не навантажують API і забезпечують реактивність у реальному часі. Polling же витрачає зайві ресурси та створює затримку.
Як налаштувати сповіщення у Slack?
Вебхук можна використовувати для оповіщення команди. Наприклад, при публікації нової статті надсилаємо повідомлення в Slack-канал:
// app/api/webhooks/sanity-slack/route.ts
export async function POST(req: Request) {
const { isValidSignature, body } = await parseBody(req, process.env.SANITY_WEBHOOK_SECRET!)
if (!isValidSignature) return Response.json({ error: 'Unauthorized' }, { status: 401 })
await fetch(process.env.SLACK_WEBHOOK_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: `📝 Нова стаття опублікована: *${body.title}*`,
attachments: [{
text: `https://yoursite.com/blog/${body.slug}`,
}],
}),
})
return Response.json({ notified: true })
}
Типові помилки при налаштуванні вебхуків
- Ігнорування Secret — зловмисник може нескінченно тригерити ревалідацію.
- Відсутність фільтра — вебхук спрацьовує на всі типи документів, включаючи системні (наприклад,
sanity.imageAsset).
- Занадто широка проекція — передаєте весь документ, хоча потрібні тільки
_id і slug. Збільшує час обробки та витрати на bandwidth.
- Немає обробки помилок — якщо зовнішній сервіс (Algolia, Slack) недоступний, вебхук падає. Додайте try-catch і чергу повторних спроб.
Перед деплоєм протестуйте вебхук за допомогою Postman або curl, надіславши POST-запит з правильним підписом. Переконайтеся, що обробник повертає 200 і кеш інвалідується. Також перевірте обробку помилок: якщо Algolia недоступний, вебхук не повинен падати — використовуйте try-catch і чергу повторних спроб.
Що входить у налаштування «під ключ»
| Компонент |
Опис |
Термін |
| Вебхук ISR |
Налаштування ендпоінту, перевірка підпису, ревалідація кешу Next.js |
0,5 дня |
| Синхронізація Algolia |
Повна індексація + інкрементальні оновлення через вебхук |
1 день |
| Сповіщення (Slack/Telegram) |
Налаштування каналу, форматування повідомлень |
0,5 дня |
| Документація |
README з описом архітектури, змінних середовища та інструкцією по деплою |
включено |
| Підтримка після запуску |
2 тижні моніторингу та виправлення помилок |
включено |
Орієнтовні терміни: від 0,5 до 3 днів залежно від кількості інтеграцій. Вартість розраховується індивідуально. Економія на інфраструктурі після впровадження вебхуків суттєва. Зв'яжіться з нами, щоб отримати точну оцінку для вашого проєкту.
Докладніше про Sanity Webhooks.
Зверніться до нас за консультацією — ми допоможемо налаштувати надійну інтеграцію Sanity з вашим стеком. Наш досвід — 10+ років розробки на Next.js і Sanity, 50+ реалізованих проєктів. Гарантуємо документацію та підтримку після запуску. Замовте аудит вашої архітектури, щоб виявити вузькі місця.
Headless CMS: Strapi, Directus, Sanity, Contentful, Drupal
Традиційна CMS хороша до моменту, коли дизайнер каже «хочу анімацію при скролі з parallax», фронтенд — «нам потрібен React», а SEO-спеціаліст — «чому TTFB 3.4 секунди». У цей момент монолітна архітектура починає заважати всім одразу. Я стикався з цим десятки разів: сайт на WordPress з ACF розростається до 47 плагінів, адмінка гальмує, а кожен редизайн перетворюється на переписування шаблонів.
Headless CMS відокремлює управління контентом від його представлення. Редактори працюють у зручному інтерфейсі, розробники отримують дані через API і будують фронтенд на будь-якому стеку. Звучить просто. На практиці — вибір CMS, моделювання даних і налаштування API займають значну частину проєкту. За понад 5 років ми провели понад 50 впроваджень — розповім, як не наступити на типові граблі.
Чому headless CMS вигідніша за моноліт?
Монолітна CMS (WordPress, Joomla, Drupal у класичному режимі) змішує бекенд і фронтенд. Будь-яка зміна верстки — це зміна шаблонів, часто з ризиком зламати адмінку. Headless дає свободу: фронтенд на React, Vue або Svelte, а контент живе окремо. Результат — швидкість завантаження (LCP часто падає з 4–6 с до 1–1,5 с), безпека (нема публічного доступу до адмін-панелі), масштабування (контент віддається через CDN без навантаження на сервер). Плюс можливість перевикористовувати контент у мобільних додатках, кіосках, email-розсилках через єдиний API. На одному проєкті це заощадило 80 годин переробок і $4000 бюджету.
Яку headless CMS обрати під проєкт?
Нема універсального інструменту. Вибір залежить від команди, складності контенту та інфраструктури. Розберемо ключові варіанти.
Strapi — open-source, self-hosted, Node.js. Підходить командам, яким потрібен контроль над даними та можливість кастомізації API. Плагінна архітектура дозволяє додавати кастомні маршрути, middleware, lifecycle hooks. REST і GraphQL з коробки. Розгортається за годину — в 3 рази швидше за Drupal. Слабке місце — версії v4 та v5 несумісні між собою, міграція болюча. Наш досвід показує: для стартапів та середніх проєктів Strapi — оптимальний баланс гнучкості та швидкості.
Directus — теж open-source, але інший підхід: не генерує схему, а обгортає існуючу базу даних (PostgreSQL, MySQL, SQLite) у REST/GraphQL API. Якщо база даних вже є — Directus підключається до неї без міграцій. Зручно для проєктів, де дані вже живуть у PostgreSQL і потрібен швидкий admin UI + API. Економія часу на етапі інтеграції — до 30%.
Sanity — хмарна CMS з real-time редактором. Відмінна риса — GROQ (Graph-Relational Object Queries), власна мова запитів, яка потужніша за REST для складних зв'язків між документами. Portable Text для структурованого контенту. Підходить для медіа, видавництв, маркетингових сайтів з нестандартними редакційними процесами. Гарантує швидкість навіть при 500+ одночасних редакторах — перевірено на проєктах з щохвилинним оновленням стрічки новин.
Contentful — enterprise хмарна CMS. Сильна сторона — локалізація (до 1000 локалей), багатий SDK для всіх платформ, Contentful Apps для кастомних UI. Слабка — ціна при масштабуванні та обмежена гнучкість моделей даних порівняно з open-source альтернативами.
Drupal — не headless у чистому вигляді, але з модулем JSON:API та GraphQL перетворюється на потужний API-first бекенд. Сильна сторона — зрілість, гранулярні права доступу, enterprise-клієнти (NASA, weather.com). Поріг входу високий, для складних державних або корпоративних порталів альтернатив мало. Ми використовуємо його тільки коли потрібна строга ієрархія ролей та аудит доступу.
| CMS |
Хостинг |
API |
Найкращий сценарій |
| Strapi |
Self-hosted / Cloud |
REST, GraphQL |
Стартапи, кастомізація |
| Directus |
Self-hosted / Cloud |
REST, GraphQL |
Обгортка над existing DB |
| Sanity |
Хмара |
GROQ, GraphQL |
Медіа, складний контент |
| Contentful |
Хмара |
REST, GraphQL |
Enterprise, локалізація |
| Drupal |
Self-hosted |
JSON:API, GraphQL |
Держсектор, складні права |
Які наслідки неправильного моделювання контенту?
Моделювання контенту — критичний етап. Помилка на цьому етапі коштує дорого. Типова проблема: поле body типу rich text для всього. Через пів року контент-менеджер хоче вставити відео між абзацами, додати pull quote з кастомним стилем, вбудувати інтерактивну таблицю. Rich text це не дозволяє. Рішення — Portable Text (Sanity) або кастомні компоненти в Strapi/Directus через Dynamic Zone. Ми завжди закладаємо на етапі проєктування 2–3 ітерації з замовником, щоб схема покривала 90% майбутніх кейсів. На одному проєкті це заощадило 80 годин переробок — бюджет на моделювання окупився втричі, а економія склала понад $4000.
Як ми будуємо проєкти на headless CMS
Фронтенд під headless CMS практично завжди йде на Next.js (App Router) або Nuxt. Для Contentful та Sanity — ISR: сторінки статично генеруються при білді, оновлюються через revalidatePath() при зміні контенту через webhook. Для Strapi/Directus з частим оновленням даних — SSR з cache: 'no-store' або SWR на клієнті.
Кейс: редизайн корпоративного сайту виробничої компанії. Попередній сайт — WordPress з ACF, 200+ сторінок, 4 мови. Проблеми: TTFB 3,8 с, редактори скаржилися на повільну адмінку.
Перейшли на Strapi (self-hosted, PostgreSQL), Next.js App Router. Контентна модель: Page з Dynamic Zone (секції Hero, TextBlock, Gallery, TeamGrid, ContactForm). Локалізація через Strapi i18n plugin + next-intl на фронтенді. Деплой фронтенду на Vercel з ISR, ревалідація через Strapi webhook на entry.publish.
TTFB з 3,8 с впав до 180 мс (статика з CDN) — різниця в 21 раз. Редактори отримали чистий інтерфейс без 47 плагінів. Вартість хостингу знизилася на $200 на місяць — це економія $2400 на рік.
Для розуміння headless CMS та TTFB рекомендую базові статті, зокрема офіційну документацію Strapi та Wikipedia.
Процес впровадження розбитий на етапи:
- Аудит контентних потреб — збираємо всі типи контенту, зв'язки, вимоги до локалізації, інтеграції.
- Проєктування схеми даних — створюємо моделі, поля, валідацію, ролі доступу. Документуємо в Swagger/OpenAPI.
- Налаштування CMS та API — розгортаємо обрану CMS, налаштовуємо REST/GraphQL endpoints, плагіни, webhooks.
- Розробка фронтенду — підключаємо Next.js/Nuxt, налаштовуємо ISR/SSR, компоненти секцій, роутинг.
- Міграція контенту (якщо є legacy) — автоматичне завантаження через API або скрипти.
- Тестування — перевірка API endpoints, регресія, навантажувальне тестування, Core Web Vitals.
- Деплой — налаштування CDN, SSL, CI/CD, моніторинг.
Скільки часу займає впровадження?
Стандартний шлях включає всі етапи. Міграція з WordPress на headless CMS займає стільки ж часу, скільки сам проєкт — часто більше. Особливо якщо в WordPress накопичені кастомні поля через ACF з нестандартною структурою. Наші середні терміни:
| Тип проєкту |
Термін |
| Простий сайт на Strapi + Next.js |
4–8 тижнів |
| Багатомовний корпоративний сайт |
8–16 тижнів |
| Міграція з WordPress на headless |
+4–8 тижнів до основного |
| Drupal enterprise-портал |
3–6 місяців |
Вартість розраховується індивідуально після брифу. Економія на хостингу за рахунок статичної генерації — до 40% на місяць.
Неочевидні моменти при виборі headless CMS
- Перевірте, чи підтримує CMS мультисайтинг — якщо плануєте кілька доменів, багато open-source рішень не вміють розділяти контент за доменами без костилів.
- Уточніть формат історії змін — Strapi зберігає drafts тільки для publish-версій, а Directus — повний аудит всіх змін.
- Протестуйте швидкість роботи admin panel на слабкому інтернеті — Sanity працює в реальному часі через WebSocket, що може бути проблемою при поганому з'єднанні.
- Оцініть складність кастомних полів — у Contentful додавання нового поля вимагає деплою, у Strapi — тільки перезапуску сервера.
- Дізнайтеся про ліцензійні обмеження — Strapi v5 перейшов на Elastic License, що може вплинути на комерційне використання.
Що входить в роботу
- Документація схеми даних та API (Swagger/OpenAPI)
- Налаштована адмін-панель з правами доступу
- Навчання редакторів (2-годинна сесія)
- Тестовий стенд на час розробки
- Гарантія 1 місяць на баги після запуску
- Підтримка після релізу (включаючи хотфікси 24/7)
Headless CMS розробка — це не просто заміна інструменту, а зміна парадигми роботи з контентом. Ми допомагаємо зробити цей перехід без простоїв та втрати даних. Отримайте консультацію та попередню оцінку — залиште заявку на сайті. Замовте впровадження headless CMS з гарантією результату.