Skip to main content

SEO Signals API

The SEO Signals API is the canonical endpoint headless storefronts use to fetch Clione's enriched SEO/AEO/GEO signals for a specific entity. It's also what powers the @clione/seo SDK under the hood.

Use it when:

  • You're building a headless / custom storefront and want to render Clione's signals in your own template.
  • You don't want to install an embed widget or theme app block.
  • You need fine-grained control over which signals you read and where you render them.

For non-headless stores (BigCommerce Stencil or Shopify Liquid themes), prefer the Schema Injector (BC) or the theme app block (Shopify) — they handle the same delivery automatically.


Endpoint

GET /api/v1/public/seo-signals/:platform/:entityType/:entityId

Path parameters:

ParamValues
platformbigcommerce | shopify
entityTypeproduct | category | collection | page
entityIdThe platform-native ID of the entity (BC product ID, Shopify product GID or numeric ID)

Authentication

Send your Clione public API key in one of three ways (in order of preference):

Authorization: Bearer sk_live_...
x-api-key: sk_live_...
?apiKey=sk_live_...

The key must have products:read scope. Generate keys from Store → Settings → API Keys.

Domain whitelisting applies: if your key has allowed domains set, the request's Origin header (or Referer, fallback) must match. Set the allowed domain to your headless storefront's domain.


Response shape

{
"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
}
}

Empty fields are omitted (not returned as null). If the entity isn't enriched, signals is {} and metadata.enrichedAt is null.


Example — 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()

Example — curl

curl -s \
-H "Authorization: Bearer sk_live_..." \
"https://api.clione.ai/api/v1/public/seo-signals/shopify/product/1234" | jq .

Rendering in Next.js (Hydrogen / Catalyst / Vue Storefront)

Most frameworks have a head / metadata API. Map the signals onto it:

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) }],
})

See @clione/seo for the SDK.


Per-platform notes

The response shape is identical across BigCommerce and Shopify. The path parameter :platform is the only difference.

BigCommerce

  • entityType: product returns full JSON-LD with aggregateRating if reviews are enabled in BC.
  • entityType: category returns meta title + description + keywords. No JSON-LD yet.
  • entityType: page returns meta title + description + keywords. No JSON-LD yet.
  • entityId is the BC numeric ID (e.g. 1234), not the slug.

Shopify

  • entityType: product returns full JSON-LD.
  • entityType: collection returns meta title + description. No JSON-LD yet.
  • entityType: page returns meta title + description. No JSON-LD yet.
  • entityId accepts both the numeric ID (1234) and the GID (gid://shopify/Product/1234).

Caching

Responses include Cache-Control: public, max-age=60. Cache on your edge (Cloudflare, Vercel) to reduce latency. Clione also caches enriched signals server-side and invalidates on enrichment, so you can safely cache longer if your traffic justifies it.


Error responses

StatusCause
401Missing or invalid API key.
403API key valid but Origin not in allowed domains, or scope missing products:read.
404Entity not found (wrong ID, wrong platform, or not synced).
429Rate limited. Backoff and retry. Limits are generous (100 req/sec/key) but headless deployments hammering a hot product can hit them.
5xxServer error. Retry with exponential backoff.

Troubleshooting

Returns 404 even though I see the product in my dashboard — The product is in Clione's DB but not for the platform you queried. Check that :platform matches the store the product was synced from. Also confirm the entity has been synced (not just created in the platform admin yesterday).

Empty signals object — Product hasn't been enriched. Enrich it first from the dashboard.

JSON-LD missing aggregateRating — Reviews are not enabled in your platform OR no products have ratings yet. See Reviews setup.