GraphQL examples
Every query in this page assumes you're hitting /graphql on a Magento install with the SEO Suite installed and configured.
Product by URL key
query ProductSeo($urlKey: String!) {
products(filter: { url_key: { eq: $urlKey } }) {
items {
sku
name
seo {
title
description
robots
canonical
open_graph {
name
content
}
structured_data
}
}
}
}
Variables:
{ "urlKey": "acme-pro-runner" }
Sample response:
{
"data": {
"products": {
"items": [
{
"sku": "AWP-001",
"name": "Acme Pro Runner",
"seo": {
"title": "Acme Pro Runner — Lightweight road shoe | Sample Store",
"description": "Acme Pro Runner: 220g neutral road shoe with 28mm stack. Free UK delivery, 30-day returns.",
"robots": "INDEX,FOLLOW",
"canonical": "https://store.example/acme-pro-runner.html",
"open_graph": [
{ "name": "og:type", "content": "product" },
{ "name": "og:title", "content": "Acme Pro Runner — Lightweight road shoe | Sample Store" },
{ "name": "og:description", "content": "Acme Pro Runner: 220g neutral road shoe..." },
{ "name": "og:url", "content": "https://store.example/acme-pro-runner.html" },
{ "name": "og:site_name", "content": "Sample Store" },
{ "name": "og:image", "content": "https://store.example/media/catalog/.../awp.jpg" },
{ "name": "twitter:card", "content": "summary_large_image" },
{ "name": "twitter:title", "content": "Acme Pro Runner — Lightweight road shoe | Sample Store" },
{ "name": "twitter:description", "content": "Acme Pro Runner: 220g neutral road shoe..." },
{ "name": "twitter:image", "content": "https://store.example/media/catalog/.../awp.jpg" }
],
"structured_data": [
"{\"@context\":\"https://schema.org/\",\"@type\":\"Product\",\"name\":\"Acme Pro Runner\",...}",
"{\"@context\":\"https://schema.org/\",\"@type\":\"BreadcrumbList\",...}"
]
}
}
]
}
}
}
Category by URL path
query CategorySeo($urlPath: String!) {
categoryList(filters: { url_path: { eq: $urlPath } }) {
name
seo {
title
description
robots
canonical
open_graph {
name
content
}
structured_data
}
}
}
Variables: { "urlPath": "shoes/running" }
CMS page by identifier
query CmsPageSeo($identifier: String!) {
cmsPage(identifier: $identifier) {
title
identifier
seo {
title
description
robots
canonical
open_graph { name content }
structured_data
}
}
}
Variables: { "identifier": "returns-policy" }
For the home page (identifier varies by store but is typically home), the response will include the Organization + WebSite JSON-LD blocks.
Just the structured data
If your storefront framework handles meta tags differently and you only want the JSON-LD blocks:
{
products(filter: { sku: { eq: "AWP-001" } }) {
items {
seo { structured_data }
}
}
}
Multi-store queries
Pass the standard Magento Store header to scope the response to a specific store:
POST /graphql
Content-Type: application/json
Store: en_us
{ "query": "{ products(...) { items { seo { title } } } }" }
The same product/category will return store-specific titles, descriptions, robots, etc.
In Next.js (App Router)
// app/products/[urlKey]/page.tsx
import type { Metadata } from 'next';
const PRODUCT_SEO_QUERY = `
query ProductSeo($urlKey: String!) {
products(filter: { url_key: { eq: $urlKey } }) {
items {
sku
name
seo {
title description robots canonical
open_graph { name content }
structured_data
}
}
}
}
`;
export async function generateMetadata({ params }: { params: { urlKey: string } }): Promise<Metadata> {
const { products } = await graphqlFetch(PRODUCT_SEO_QUERY, { urlKey: params.urlKey });
const seo = products.items[0]?.seo;
if (!seo) return {};
const og = Object.fromEntries(seo.open_graph.map((t: any) => [t.name, t.content]));
return {
title: seo.title,
description: seo.description,
robots: seo.robots ?? undefined,
alternates: { canonical: seo.canonical },
openGraph: {
type: og['og:type'] === 'product' ? 'website' : 'website',
title: og['og:title'],
description: og['og:description'],
url: og['og:url'],
siteName: og['og:site_name'],
images: og['og:image'] ? [og['og:image']] : undefined,
},
twitter: {
card: og['twitter:card'] as any,
title: og['twitter:title'],
description: og['twitter:description'],
images: og['twitter:image'] ? [og['twitter:image']] : undefined,
},
};
}
export default async function ProductPage({ params }: { params: { urlKey: string } }) {
const { products } = await graphqlFetch(PRODUCT_SEO_QUERY, { urlKey: params.urlKey });
const product = products.items[0];
return (
<>
{product.seo.structured_data.map((json: string, i: number) => (
<script
key={i}
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: json }}
/>
))}
<h1>{product.name}</h1>
{/* …rest of product UI… */}
</>
);
}
In Apollo Client (TypeScript)
import { gql, useQuery } from '@apollo/client';
const PRODUCT_SEO_QUERY = gql`
query ProductSeo($urlKey: String!) {
products(filter: { url_key: { eq: $urlKey } }) {
items {
sku
name
seo {
title description robots canonical
open_graph { name content }
structured_data
}
}
}
}
`;
function useProductSeo(urlKey: string) {
return useQuery(PRODUCT_SEO_QUERY, { variables: { urlKey } });
}