SEO Signals API
La SEO Signals API es el endpoint canónico que los storefronts headless usan para ir a buscar las señales SEO/AEO/GEO enriquecidas de Clione para una entidad concreta. También es lo que alimenta el SDK @clione/seo por debajo.
Úsala cuando:
- Estás construyendo un storefront headless / a medida y quieres renderizar las señales de Clione en tu propia plantilla.
- No quieres instalar un widget de embed o un theme app block.
- Necesitas control fino sobre qué señales lees y dónde las renderizas.
Para tiendas no-headless (BigCommerce Stencil o temas Liquid de Shopify), prefiere el Schema Injector (BC) o el theme app block (Shopify) — gestionan la misma entrega automáticamente.
Endpoint
GET /api/v1/public/seo-signals/:platform/:entityType/:entityId
Parámetros de path:
| Param | Valores |
|---|---|
platform | bigcommerce | shopify |
entityType | product | category | collection | page |
entityId | El ID nativo de la plataforma para la entidad (ID de producto de BC, GID o ID numérico de producto de Shopify) |
Autenticación
Envía tu API key pública de Clione de una de tres maneras (por orden de preferencia):
Authorization: Bearer sk_live_...
x-api-key: sk_live_...
?apiKey=sk_live_...
La key debe tener scope products:read. Genera keys desde Store → Settings → API Keys.
Aplica la lista blanca de dominios: si tu key tiene allowed domains configurados, el header Origin (o Referer, fallback) de la petición debe coincidir. Pon el dominio permitido al dominio de tu storefront headless.
Forma de la respuesta
{
"entity": {
"id": "1234",
"platform": "shopify",
"entityType": "product",
"name": "Linen bed sheet set",
"url": "https://shop.example.com/products/linen-sheet-set"
},
"signals": {
"metaTitle": "Linen Bed Sheet Set — Cool, Breathable, Made in Portugal",
"metaDescription": "Pure European linen sheet set ideal for hot sleepers...",
"canonicalUrl": "https://shop.example.com/products/linen-sheet-set",
"keywords": ["linen sheets", "breathable bedding", "summer bedding", "sábanas de lino"],
"ogTags": {
"title": "Linen Bed Sheet Set",
"description": "Cool, breathable bedding...",
"image": "https://cdn.example.com/linen.jpg",
"type": "product"
},
"jsonLd": {
"@context": "https://schema.org",
"@type": "Product",
"name": "Linen Bed Sheet Set",
"description": "...",
"keywords": "linen sheets, breathable bedding...",
"offers": {
"@type": "Offer",
"price": "129.00",
"priceCurrency": "EUR"
}
}
},
"metadata": {
"enrichedAt": "2026-05-30T11:23:45.000Z",
"version": 4
}
}
Los campos vacíos se omiten (no se devuelven como null). Si la entidad no está enriquecida, signals es {} y metadata.enrichedAt es null.
Ejemplo — fetch
const apiKey = process.env.CLIONE_API_KEY
const platform = 'shopify'
const productId = '1234'
const res = await fetch(
`https://api.clione.ai/api/v1/public/seo-signals/${platform}/product/${productId}`,
{
headers: { Authorization: `Bearer ${apiKey}` },
},
)
if (!res.ok) throw new Error(`Clione SEO Signals: ${res.status}`)
const { signals, entity } = await res.json()
Ejemplo — curl
curl -s \
-H "Authorization: Bearer sk_live_..." \
"https://api.clione.ai/api/v1/public/seo-signals/shopify/product/1234" | jq .
Renderizar en Next.js (Hydrogen / Catalyst / Vue Storefront)
La mayoría de frameworks tienen una API de head / metadata. Mapea las señales sobre ella:
Next.js App Router
import { getSignals } from '@clione/seo'
export async function generateMetadata({ params }) {
const { signals, entity } = await getSignals('product', params.id, {
apiKey: process.env.CLIONE_API_KEY,
storeId: process.env.CLIONE_STORE_ID,
platform: 'shopify',
})
return {
title: signals.metaTitle,
description: signals.metaDescription,
alternates: { canonical: signals.canonicalUrl },
openGraph: signals.ogTags,
other: {
'script:ld+json': JSON.stringify(signals.jsonLd),
},
}
}
Nuxt / Vue Storefront
import { useClioneSignals } from '@clione/seo/nuxt'
const { signals } = await useClioneSignals('product', productId)
useHead({
title: signals.metaTitle,
meta: [
{ name: 'description', content: signals.metaDescription },
...Object.entries(signals.ogTags).map(([k, v]) => ({ property: `og:${k}`, content: v })),
],
link: [{ rel: 'canonical', href: signals.canonicalUrl }],
script: [{ type: 'application/ld+json', innerHTML: JSON.stringify(signals.jsonLd) }],
})
Mira @clione/seo para el SDK.
Notas por plataforma
La forma de la respuesta es idéntica entre BigCommerce y Shopify. El parámetro de path :platform es la única diferencia.
BigCommerce
entityType: productdevuelve JSON-LD completo conaggregateRatingsi las reviews están activadas en BC.entityType: categorydevuelve meta title + description + keywords. Sin JSON-LD aún.entityType: pagedevuelve meta title + description + keywords. Sin JSON-LD aún.entityIdes el ID numérico de BC (p. ej.1234), no el slug.
Shopify
entityType: productdevuelve JSON-LD completo.entityType: collectiondevuelve meta title + description. Sin JSON-LD aún.entityType: pagedevuelve meta title + description. Sin JSON-LD aún.entityIdacepta tanto el ID numérico (1234) como el GID (gid://shopify/Product/1234).
Caché
Las respuestas incluyen Cache-Control: public, max-age=60. Cachea en tu edge (Cloudflare, Vercel) para reducir latencia. Clione también cachea las señales enriquecidas server-side e invalida al enriquecer, así que puedes cachear más tiempo si tu tráfico lo justifica.
Respuestas de error
| Status | Causa |
|---|---|
| 401 | API key ausente o inválida. |
| 403 | API key válida pero el Origin no está en los allowed domains, o falta el scope products:read. |
| 404 | Entidad no encontrada (ID equivocado, plataforma equivocada, o no sincronizada). |
| 429 | Rate limit. Backoff y reintenta. Los límites son generosos (100 req/seg/key) pero deployments headless martilleando un producto caliente pueden alcanzarlos. |
| 5xx | Error del servidor. Reintenta con backoff exponencial. |
Solución de problemas
Devuelve 404 aunque veo el producto en mi dashboard — El producto está en la BBDD de Clione pero no para la plataforma que consultaste. Revisa que :platform coincida con la tienda desde la que se sincronizó el producto. Confirma también que la entidad ha sido sincronizada (no solo creada en el admin de la plataforma ayer).
Objeto signals vacío — El producto no se ha enriquecido. Enriquécelo primero desde el dashboard.
JSON-LD sin aggregateRating — Las reviews no están activadas en tu plataforma O ningún producto tiene ratings aún. Mira Configuración de Reviews.