Diil Docs
  1. Documentación
  2. Primeros pasos

Inicio rápido: tu primera petición en cinco minutos

Actualizado:

Cinco minutos, una página, cero paneles de administración. Al final de esta guía, un titular de tu web vendrá del CRM de Diil, y tus editores podrán cambiarlo con un clic encima. Prepárate un café; igual no te da tiempo a terminártelo.

Vas a necesitar:

  • acceso a un sitio en el CRM de Diil (puedes crear uno nuevo para trastear);
  • una terminal con curl o cualquier herramienta que sepa enviar una petición HTTP;
  • cualquier frontend: un HTML a pelo, React, Next.js, Nuxt… tú decides.

Prepara el contenido y una clave

  1. Crea algo de contenido en el CRM

    Abre tu sitio en el CRM y comprueba que tiene los idiomas que necesitas (por ejemplo, inglés). Después crea:

    • una página con el marcador home;
    • dentro, una sección con el marcador hero;
    • y dentro de esta, un bloque de texto con el marcador hero_title; escribe un titular en él.

    Los marcadores son los nombres con los que tu código encuentra el contenido: letras latinas, dígitos y guiones bajos, de 2 a 40 caracteres, distinguiendo mayúsculas. Elígelos como si fueran nombres de variables: van a vivir mucho tiempo en tu código. Aquí tienes la foto completa de páginas, secciones y bloques.

  2. Consigue una clave de sitio

    Ve a Ajustes → Claves de Content API y crea una clave. Tiene la forma pk_ seguido de 32 caracteres hexadecimales y está ligada a este sitio en concreto.

    Una clave nueva suele funcionar al momento; en el peor de los casos, dale unos minutos. Revocar funciona igual: las claves revocadas reciben 401 invalid_key.

  3. Haz tu primera petición

    Pide la página home en inglés:

    curl "https://back.sitecog.com/content/v1/pages/home?lang=en" \
      -H "x-crm-key: pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40"
    200 OKjson
    {
      "id": 26,
      "marker": "home",
      "name": "Home",
      "href": "/",
      "index": 0,
      "params": {},
      "content": {
        "hero": {
          "id": 41,
          "marker": "hero",
          "name": "Hero",
          "index": 0,
          "show": true,
          "content": {
            "hero_title": {
              "id": 95,
              "marker": "hero_title",
              "name": "Hero title",
              "type": "text",
              "multilang": true,
              "updatedAt": "2026-09-20T16:33:23.000Z",
              "content": { "en": "Earbuds that mute the city" }
            }
          }
        }
      }
    }

    ¿Ves el camino hasta tu titular? content.hero.content.hero_title.content.en: página → sección → bloque → idioma. Todas las páginas tienen exactamente esta forma; los detalles, en Páginas.

Muéstralo en tu página

La misma petición en cuatro sabores. Elige el tuyo: todos hacen lo mismo, traer la página y meter el titular en un <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>

Dónde guardar la clave

Pon la clave en una variable de entorno en lugar de en el código; no porque sea secreta, sino porque así cambiar de sitio o rotar claves se queda en un cambio de una línea.

.env.localbash
# .env.local (Next.js) — solo en el servidor, nunca llega al navegador
CRM_KEY=pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40

# El código del navegador necesita una variable pública. No pasa nada: la clave es de solo lectura.
NEXT_PUBLIC_CRM_KEY=pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40
# Vite: VITE_CRM_KEY=…   Nuxt: NUXT_PUBLIC_CRM_KEY=…

En un componente de servidor (como en la pestaña de Next.js de arriba) usa la variable solo de servidor: la clave nunca sale de tu servidor. Para el código del navegador, una variable pública está perfectamente bien.

Añade un helper de idiomas

Los bloques de texto llegan como mapas de idiomas: { "en": "…", "de": "…" }. La API nunca cambia un idioma por otro: si falta una traducción, sencillamente no está (o es una cadena vacía si el editor dejó el campo en blanco). Elegir un respaldo es cosa tuya, y este helper diminuto lo deja en una sola línea:

// lib/t.js
// Elige una traducción: idioma pedido → idioma de respaldo → la primera no vacía → ''
export function t(map, lang, fallback = 'en') {
  if (!map) return '';
  return map[lang] || map[fallback] || Object.values(map).find(Boolean) || '';
}
Usojs
// Pide el idioma del visitante y el de respaldo en una sola petición
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'); // ¿el alemán aún no está rellenado? → el texto en inglés

Cada código en ?lang= tiene que ser un idioma activo del sitio; si no, recibes 400 unknown_lang con la lista de los disponibles. Si omites lang, te llegan todos los idiomas activos de golpe. La historia completa, en Idiomas y respaldo.

Activa la edición en vivo

Ahora viene lo divertido. Tu página ya muestra contenido del CRM; vamos a dejar que los editores lo cambien directamente en la página, sin buscar el campo correcto en un formulario.

  1. Añade el widget

    Un script, una vez por página, justo antes de </body>. Solo carga el editor cuando tu sitio se abre dentro del CRM, así que los visitantes normales no descargan ni un byte.

    <script src="https://widget.sitecog.com/widget.js" defer></script>
  2. Dile al editor qué elemento muestra qué bloque

    Añade data-crm-text con el marcador del bloque al elemento que lo pinta. Sigue renderizando el texto de la API como hasta ahora: el atributo solo conecta el elemento con el bloque.

    <body>
      <h1 data-crm-text="hero_title">Earbuds that mute the city</h1>
    
      <!-- una vez por página, justo antes de </body> -->
      <script src="https://widget.sitecog.com/widget.js" defer></script>
    </body>

    Las imágenes, los vídeos, los objetos y los arrays tienen sus propios atributos (data-crm-image, data-crm-video, data-crm-object, data-crm-array): mira Widget y marcado. Los atributos no molestan a los visitantes, así que déjalos en producción.

  3. Deja que el CRM meta tu sitio en un iframe

    El modo Live abre tu sitio dentro del CRM, en un iframe. Tu servidor tiene que permitirlo con frame-ancestors y no debe enviar X-Frame-Options: DENY ni SAMEORIGIN. Si no, el CRM te dirá que el sitio prohíbe que lo incrusten.

    // next.config.js
    module.exports = {
      async headers() {
        return [{
          source: '/:path*',
          headers: [
            { key: 'Content-Security-Policy', value: "frame-ancestors 'self' https://sitecog.com" },
          ],
        }];
      },
    };
  4. Clic, escribe, guarda

    Abre tu sitio en el CRM en modo Live, haz clic en el titular, cámbialo y guarda. El CRM escribe el bloque, la versión del contenido sube, tu página trae el contenido fresco… y ahí está el titular nuevo. 🎉

    Extra: si pones data-crm-text="promo_note" en un elemento antes de que exista ese bloque, el editor puede crear el bloque directamente desde el sitio.

Sáltate la caché para los editores

Nuestro lado nunca sirve contenido viejo en modo Live. Pero tu caché sí puede: con revalidate: 60 un editor podría guardar y seguir viendo el texto antiguo hasta un minuto. Dentro del marco del CRM la URL lleva ?crm_live=1; úsalo para hacer la petición con cache: 'no-store':

// app/page.tsx — sáltate cualquier caché mientras un editor está mirando
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>;
}

Y ahora qué

Ya tienes el contenido fluyendo y a los editores haciendo clic. Por aquí puedes seguir profundizando: