Centro de ayuda

Documentación de integraciones

Conecta Indexal con tu sitio para publicar cada artículo en tu propio dominio. No necesitas acceso al backend de Indexal.

Inicio rápido

La configuración pertenece al dominio activo. Si gestionas varios proyectos, elige primero el dominio correcto en el selector del sidebar.

  1. 1

    Elige el proyecto

    Comprueba el dominio activo en la esquina superior izquierda.
  2. 2

    Abre Conectar sitio

    Ve a Conectar sitio y selecciona una integración.
  3. 3

    Agrega las credenciales

    Indexal valida la conexión antes de guardarla. Las claves de WordPress, Ghost y Shopify se almacenan cifradas.
  4. 4

    Publica una prueba

    Abre un artículo del calendario y pulsa Publicar. Puedes conectar varios destinos; todos reciben el artículo.
Sin integración: activa el blog alojado y tendrás una URL indexable sin instalar nada.

Revisión antes de publicar

El contenido generado no tiene que publicarse sin supervisión. Desde “Ver artículo” puedes revisar y modificar la versión que recibirá el sitio conectado.

Título y meta descripción
Autor y biografía
Contenido Markdown completo
Enlaces dentro del artículo
Texto y URL del CTA
Idioma y versiones relacionadas

Cómo funciona el guardado

  1. Guardar cambios actualiza el borrador sin publicarlo.
  2. Insertar CTA añade al contenido un enlace Markdown con el texto y URL indicados.
  3. Guardar y publicar guarda primero la revisión y después entrega exactamente esa versión.
  4. El tiempo de lectura se recalcula automáticamente a partir del contenido final, usando 220 palabras por minuto.
Qué recibe el destino: título, meta descripción, HTML, Markdown, enlaces, conteo de palabras, minutos de lectura, autor, biografía, logo, CTA estructurado, idioma, datos para relacionar traducciones, y las URLs de portada e infografía cuando estén activadas (el webhook debe insertar la infografía dentro del cuerpo del artículo; Indexal no la agrega automáticamente al HTML).

WordPress

Publica mediante la API REST incluida en WordPress. No uses la contraseña normal de tu cuenta.

  1. 1

    Crea una contraseña de aplicación

    En WordPress abre Usuarios → Perfil → Contraseñas de aplicación, escribe “Indexal” y pulsa Añadir.
  2. 2

    Conecta el sitio

    En Indexal ingresa la URL completa, tu usuario y la contraseña de aplicación generada.
  3. 3

    Verifica permisos

    El usuario debe poder crear y publicar entradas. La API /wp-json/wp/v2/posts debe estar accesible.

Ghost

Usa una integración personalizada de Ghost Admin API para crear publicaciones con imagen, etiquetas y metadatos SEO.

  1. 1

    Crea la integración

    En Ghost abre Settings → Integrations → Add custom integration.
  2. 2

    Copia la Admin API key

    Copia la clave completa con formato id:secret. La Content API key no sirve para publicar.
  3. 3

    Conecta y valida

    Ingresa la URL del blog y la clave. Indexal comprobará las credenciales antes de guardarlas.

Shopify

Publica artículos en el blog de tu tienda mediante una app personalizada.

  1. 1

    Crea una app

    En Shopify abre Configuración → Apps y canales de venta → Desarrollar apps.
  2. 2

    Concede acceso

    Activa el permiso de Admin API write_content, instala la app y copia el token.
  3. 3

    Selecciona el blog

    Ingresa el dominio tienda.myshopify.com. Si tienes varios blogs, añade el handle; si lo dejas vacío se usará el primero.

RSS y plataformas sin conexión directa

El feed sirve para importar o automatizar publicaciones en Wix, Squarespace y otros CMS.

Activa “Feed RSS” en Conectar sitio. La dirección tendrá este formato:

https://TU-DOMINIO-DE-INDEXAL/blog/tu-sitio.com/feed.xml

Para Webflow, HubSpot, Framer, Duda, Notion o un sitio propio, recomendamos el webhook porque entrega el HTML completo en tiempo real.

Sitios bilingües y multidioma

Indexal envía una publicación independiente por cada idioma configurado. Si el proyecto usa ES + EN, el destino recibirá dos entregas relacionadas.

Regla principal: cada idioma necesita su propia URL. No guardes español e inglés sobre el mismo slug o registro del CMS.

Campos para identificar cada versión

CampoUso
languageCodeIdioma ISO 639-1: es, en, pt, etc.
translationGroupIdEl mismo identificador para todas las versiones del artículo.
parentArticleIdNulo en el original; ID del original en las traducciones.
isTranslationIndica si esta entrega es una traducción.
idID único de esta versión; úsalo para actualizar sin duplicar.

Implementación recomendada

  1. Guarda languageCode junto al contenido y úsalo en <html lang>.
  2. Crea rutas separadas, por ejemplo /es/blog/slug y /en/blog/slug.
  3. Agrupa las versiones por translationGroupId.
  4. Configura canonical hacia la URL de esa misma versión y enlaces hreflang hacia las demás.
  5. Devuelve a Indexal la URL pública correspondiente a cada entrega.
// Ejemplo conceptual: una URL distinta por idioma
const language = payload.languageCode; // "es", "en", etc.
const publicPath = "/" + language + "/blog/" + payload.slug;

await cms.upsertArticle({
  externalId: payload.id,                 // idempotencia de esta versión
  translationGroup: payload.translationGroupId, // relaciona ES con EN
  language,
  path: publicPath,
  title: payload.title,
  html: payload.contentHtml,
  metaDescription: payload.metaDescription,
});

// Devuelve la URL correspondiente a ESTA versión.
return Response.json({ url: "https://tusitio.com" + publicPath });
WordPress, Ghost y Shopify: Indexal crea una entrada por idioma. Para administrar relaciones multidioma nativas del CMS (por ejemplo, WPML o Polylang), utiliza el webhook y adapta el ejemplo a la API del plugin o del CMS.

Webhook firmado

Indexal envía un POST JSON cuando se publica un artículo. Tu endpoint debe usar HTTPS, responder en menos de 15 segundos y devolver un estado 2xx.

Cuerpo de la solicitud

{
  "id": "article_uuid",
  "title": "Título del artículo",
  "slug": "titulo-del-articulo",
  "metaDescription": "Descripción para buscadores",
  "contentHtml": "<article>...</article>",
  "contentMarkdown": "# Título...",
  "heroImageUrl": "https://.../hero.png",
  "heroImageAlt": "Texto alternativo de la portada",
  "infographicImageUrl": "https://…supabase.co/storage/v1/object/public/article-images/…webp",
  "infographicHtml": "<figure class="ixig">...</figure>",
  "keywords": ["keyword principal"],
  "faqSchema": [],
  "languageCode": "es",
  "translationGroupId": "original_article_uuid",
  "parentArticleId": null,
  "isTranslation": false,
  "wordCount": 1840,
  "readingTimeMinutes": 9,
  "author": {
    "name": "Nombre del autor",
    "bio": "Biografía breve",
    "logoUrl": "https://.../logo.webp"
  },
  "cta": {
    "url": "https://tusitio.com/contacto",
    "label": "Agenda una demo",
    "asButton": true
  },
  "status": "published",
  "publishedAt": "2026-07-31T12:00:00.000Z",
  "canonicalUrl": "https://app.indexal.com/blog/dominio.com/slug"
}

Portada e infografía

heroImageUrl es la portada del artículo: úsala como imagen destacada (featured image / og:image), fuera del cuerpo del texto, con heroImageAlt en su atributo alt.

infographicImageUrl es la infografía como imagen WebP, y es la que deberías usar: un <img src> lo acepta cualquier sanitizador, así que llega bien sin que configures nada. Mide 2400px de ancho, pesa unos 300 KB y se genera la primera vez que alguien la pide. Ya viene insertada dentro de contentHtml, justo después de la introducción.

infographicHtml es la misma infografía en HTML — es de ahí que se rasteriza la imagen. Es más nítida y se readapta al ancho, pero solo sirve si tu integración no sanitiza el HTML: los sanitizadores borran la etiqueta style que lleva dentro y queda como texto suelto. Si quieres esta versión y sanitizas, enlaza una vez la hoja de estilos con <link rel="stylesheet" href="https://getindexal.com/infographic.css"> y basta con que se conserve el atributo class.

Si no quieres pensar en esto, usa contentHtml tal cual: ya trae la imagen en su sitio.

Ambos campos pueden llegar como null: la portada está desactivada, la infografía no está activada en Ajustes de contenido, o su generación falló. En ese caso omite el elemento correspondiente sin bloquear la publicación del resto del artículo.

Cabeceras

CabeceraUso
X-Indexal-Eventarticle.published
X-Indexal-LanguageIdioma ISO 639-1 de esta versión
X-Indexal-TimestampFecha Unix usada para evitar reenvíos maliciosos
X-Indexal-SignatureFirma HMAC SHA-256 del cuerpo original
X-Indexal-DeliveryUUID único para deduplicar entregas

Verificar la firma en Node.js

import crypto from "node:crypto";

export function verifyIndexal(rawBody, headers, secret) {
  const timestamp = headers["x-indexal-timestamp"];
  const received = headers["x-indexal-signature"] || "";
  const expected = "sha256=" + crypto
    .createHmac("sha256", secret)
    .update(timestamp + "." + rawBody)
    .digest("hex");

  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
  const a = Buffer.from(received);
  const b = Buffer.from(expected);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Calcula la firma con el cuerpo crudo, antes de convertirlo a JSON. Si respondes { "url": "https://tusitio.com/blog/slug" }, Indexal guardará esa dirección como URL final.

Solución de errores

WordPress responde 401 o 403

Genera una contraseña de aplicación nueva y confirma que el usuario puede publicar entradas. Algunos plugins de seguridad bloquean la API REST.

Ghost rechaza la clave

Usa la Admin API key completa de una integración personalizada, no la Content API key.

Shopify no encuentra blogs

Crea primero un blog en Contenido → Publicaciones de blog y reinstala la app después de conceder write_content.

El webhook falla

Comprueba HTTPS, respuesta 2xx en menos de 15 segundos y que la URL no redirija. Registra X-Indexal-Delivery para localizar la entrega.

Se publica en el proyecto incorrecto

Cambia el dominio activo en el sidebar antes de configurar la integración; cada proyecto conserva destinos separados.