Diil Docs
  1. Документация
  2. С чего начать

Быстрый старт: первый запрос за пять минут

Обновлено:

Пять минут, одна страница и ни одной самописной админки. К концу этого руководства заголовок на вашем сайте будет приходить из CRM Diil, а редакторы смогут поменять его, просто кликнув по нему. Наливайте кофе — допить, возможно, не успеете.

Понадобится:

  • доступ к сайту в CRM Diil (для опытов можно завести отдельный);
  • терминал с curl или любой другой способ отправить HTTP-запрос;
  • любой фронтенд: обычный HTML-файл, React, Next.js, Nuxt — как вам удобнее.

Контент и ключ

  1. Заведите контент в CRM

    Откройте сайт в CRM и проверьте, что нужные языки добавлены (например, английский). Затем создайте:

    • страницу с маркером home;
    • в ней — секцию с маркером hero;
    • в секции — текстовый блок с маркером hero_title, и впишите в него заголовок.

    Маркер — это имя, по которому ваш код находит контент: латиница, цифры и подчёркивание, от 2 до 40 символов, регистр важен. Выбирайте их как имена переменных — жить в коде им долго. Как всё устроено целиком — в разделе «Как устроен контент».

  2. Получите ключ сайта

    Откройте Настройки → Ключи контентного API и создайте ключ. Он выглядит как pk_ и 32 шестнадцатеричных символа и привязан к этому сайту.

    Обычно новый ключ работает сразу, в худшем случае — через несколько минут. С отзывом так же: на отозванный ключ API отвечает 401 invalid_key.

  3. Сделайте первый запрос

    Запросим страницу home на английском:

    curl "https://back.sitecog.com/content/v1/pages/home?lang=en" \
      -H "x-crm-key: pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40"
    200 OKjson
    {
      "id": 26,
      "marker": "home",
      "name": "Главная",
      "href": "/",
      "index": 0,
      "params": {},
      "content": {
        "hero": {
          "id": 41,
          "marker": "hero",
          "name": "Первый экран",
          "index": 0,
          "show": true,
          "content": {
            "hero_title": {
              "id": 95,
              "marker": "hero_title",
              "name": "Заголовок первого экрана",
              "type": "text",
              "multilang": true,
              "updatedAt": "2026-09-20T16:33:23.000Z",
              "content": { "en": "Earbuds that mute the city" }
            }
          }
        }
      }
    }

    Видите путь к заголовку? content.hero.content.hero_title.content.en — страница → секция → блок → язык. Любая страница устроена ровно так же; все подробности — в разделе «Страницы».

Выводим на страницу

Один и тот же запрос в четырёх вариантах. Выбирайте свой — все делают одно и то же: забирают страницу и кладут заголовок в <h1>.

<h1 id="hero-title"></h1>

<script type="module">
  const res = await fetch('https://back.sitecog.com/content/v1/pages/home?lang=en', {
    headers: { 'x-crm-key': 'pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40' },
  });
  const page = await res.json();
  const hero = page.content.hero.content;

  document.getElementById('hero-title').textContent = hero.hero_title.content.en;
</script>

Где хранить ключ

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

.env.localbash
# .env.local (Next.js) — только для сервера, в браузер не попадает
CRM_KEY=pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40

# Коду в браузере нужна публичная переменная. И это нормально: ключ только читает.
NEXT_PUBLIC_CRM_KEY=pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40
# Vite: VITE_CRM_KEY=…   Nuxt: NUXT_PUBLIC_CRM_KEY=…

В серверном компоненте (как во вкладке Next.js выше) берите серверную переменную — ключ так и не покинет ваш сервер. Для кода в браузере публичная переменная — совершенно нормальный вариант.

Помощник для переводов

Текстовые блоки приходят картой переводов: { "en": "…", "de": "…" }. Сам API один язык другим не подменяет: если перевода нет, его просто нет в ответе (или там пустая строка, если редактор оставил поле пустым). Какой язык показать взамен — решаете вы, и с этим помощником это одна строка:

// lib/t.js
// Выбираем перевод: нужный язык → запасной → первый непустой → ''
export function t(map, lang, fallback = 'en') {
  if (!map) return '';
  return map[lang] || map[fallback] || Object.values(map).find(Boolean) || '';
}
Как пользоватьсяjs
// Язык посетителя и запасной — одним запросом
const res = await fetch('https://back.sitecog.com/content/v1/pages/home?lang=de,en', {
  headers: { 'x-crm-key': 'pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40' },
});
const page = await res.json();
const hero = page.content.hero.content;

t(hero.hero_title.content, 'de');       // "Kopfhörer, die die Stadt stummschalten"
t(hero.hero_title.content, 'de', 'en'); // немецкий ещё не заполнили? → английский текст

Каждый код в ?lang= должен быть активным языком сайта, иначе придёт 400 unknown_lang со списком доступных. Без lang вернутся сразу все активные языки. Вся история целиком — в разделе «Языки и запасной язык».

Включаем правку на сайте

А теперь самое приятное. Страница уже показывает контент из CRM — осталось дать редакторам менять его прямо на странице, не выискивая нужное поле в форме.

  1. Подключите виджет

    Один скрипт, один раз на страницу, прямо перед </body>. Редактор он подгружает только тогда, когда сайт открыт внутри CRM, — обычные посетители не скачивают из него ни байта.

    <script src="https://widget.sitecog.com/widget.js" defer></script>
  2. Подскажите редактору, где какой блок

    Добавьте элементу, который выводит блок, атрибут data-crm-text с маркером блока. Сам текст по-прежнему берите из API — атрибут лишь связывает элемент с блоком.

    <body>
      <h1 data-crm-text="hero_title">Earbuds that mute the city</h1>
    
      <!-- один раз на страницу, прямо перед </body> -->
      <script src="https://widget.sitecog.com/widget.js" defer></script>
    </body>

    У картинок, видео, объектов и списков свои атрибуты (data-crm-image, data-crm-video, data-crm-object, data-crm-array) — о них в разделе «Виджет и разметка». Посетителям атрибуты ничем не мешают, так что смело оставляйте их в продакшене.

  3. Разрешите CRM открывать сайт во фрейме

    Режим Live открывает ваш сайт внутри CRM, в iframe. Сервер должен разрешить это через frame-ancestors и не отдавать X-Frame-Options: DENY или SAMEORIGIN. Иначе CRM сообщит, что сайт запрещает встраивание.

    // next.config.js
    module.exports = {
      async headers() {
        return [{
          source: '/:path*',
          headers: [
            { key: 'Content-Security-Policy', value: "frame-ancestors 'self' https://sitecog.com" },
          ],
        }];
      },
    };
  4. Кликните, поправьте, сохраните

    Откройте сайт в CRM в режиме Live, кликните по заголовку, измените его и сохраните. CRM запишет блок, версия контента поднимется, страница заберёт свежие данные — и новый заголовок уже на месте. 🎉

    Бонус: если повесить data-crm-text="promo_note" на элемент раньше, чем такой блок появился в CRM, редактор сможет создать блок прямо с сайта.

Без кэша для редакторов

С нашей стороны в режиме Live устаревшего контента не бывает. А вот ваш кэш может подвести: с revalidate: 60 редактор сохранит правку и ещё до минуты будет видеть старый текст. Внутри рамки CRM к адресу добавляется ?crm_live=1 — по нему и запрашивайте контент с cache: 'no-store':

// app/page.tsx — пока смотрит редактор, никакого кэша
const API = 'https://back.sitecog.com/content';

export default async function Home({ searchParams }: { searchParams: Promise<{ crm_live?: string }> }) {
  const live = (await searchParams).crm_live === '1';

  const res = await fetch(API + '/v1/pages/home?lang=en', {
    headers: { 'x-crm-key': process.env.CRM_KEY! },
    ...(live ? { cache: 'no-store' as const } : { next: { revalidate: 60 } }),
  });
  const page = await res.json();
  const hero = page.content.hero.content;

  return <h1 data-crm-text="hero_title">{hero.hero_title.content.en}</h1>;
}

Что дальше

Контент приходит, редакторы кликают. Вот куда копать дальше: