Fetch Yoast SEO metadata from WordPress via a Supabase Edge Function that calls the WordPress REST API and reads the Yoast SEO fields from each post and page response. Extract meta title, meta description, canonical URL, Open Graph tags, Twitter card data, and JSON-LD schema to use in your Lovable app's React Helmet head tags. Yoast SEO data is specific to metadata extraction, unlike the general WordPress integration which covers all content.
Sync Yoast SEO metadata from WordPress to your headless Lovable frontend
When building a headless WordPress frontend with Lovable, content SEO is a critical challenge. Traditional WordPress SEO plugins like Yoast inject meta tags directly into the HTML head via PHP server rendering. In a headless architecture, that PHP rendering is bypassed — your Lovable React frontend handles the HTML output, which means meta tags must be explicitly added by the frontend code. Without this, every page on your Lovable site shares the same default meta tags, destroying the SEO value that your editors have built up in Yoast over months or years.
Yoast SEO Free (version 14.0+) automatically includes all configured SEO metadata in the WordPress REST API response. Each post and page response includes a 'yoast_head_json' object containing: the meta title (title_template merged with post name), meta description, canonical URL, robots directives (noindex, nofollow), Open Graph title/description/image for Facebook/LinkedIn sharing, Twitter card title/description/image, and the full JSON-LD schema graph (Article, BreadcrumbList, WebSite, Organization schemas). This is everything needed to replicate Yoast's SEO output in your Lovable frontend.
This integration specifically targets the SEO metadata extraction use case. The general WordPress integration covers fetching post content and media. This integration focuses on the yoast_head_json field and how to translate it into React Helmet (or React 19's native head management) tags. For organizations with mature Yoast configurations — custom meta templates, focus keyword settings, schema configurations — preserving that SEO infrastructure in the headless migration is essential.
Integration method
Yoast SEO metadata integrates with Lovable through a Supabase Edge Function that calls the WordPress REST API with the Yoast SEO fields included in the response. Yoast SEO (Free) adds a 'yoast_head_json' object to each post and page API response containing all SEO metadata. The Edge Function fetches this metadata and returns it to the React frontend, where it is applied to the page's head tags using React Helmet or a similar library.
Prerequisites
- A WordPress installation with Yoast SEO plugin installed and activated (version 14.0+ for yoast_head_json in REST API)
- The WordPress site's REST API accessible from the Edge Function (verified by visiting yourdomain.com/wp-json/wp/v2/posts in browser)
- For Yoast SEO Free: yoast_head_json is automatically included in REST responses (no extra plugin needed)
- A Lovable app with the general WordPress proxy Edge Function already configured, or set up per the WordPress integration guide
- React Helmet or react-helmet-async installed in the Lovable project for applying meta tags
Step-by-step guide
Verify Yoast SEO data appears in WordPress REST API responses
Verify Yoast SEO data appears in WordPress REST API responses
Before writing any Edge Function code, confirm that your WordPress installation's REST API includes Yoast SEO metadata in post responses. This requires Yoast SEO Free version 14.0 or later to be installed and activated. To verify, open your browser and visit: https://yoursite.com/wp-json/wp/v2/posts?per_page=1 The response JSON should include a 'yoast_head' field containing the full HTML meta tag block (as a string) and a 'yoast_head_json' field containing the parsed metadata as a JSON object. The 'yoast_head_json' object should contain keys like: title, description, robots, og_locale, og_type, og_title, og_description, og_url, og_site_name, og_image, twitter_card, twitter_creator, schema. If you do not see these fields, verify: 1. Yoast SEO plugin is activated in WordPress admin → Plugins 2. Yoast SEO version is 14.0 or newer (SEO → General → Features shows the version) 3. The REST API is accessible (try /wp-json/ root to confirm the API responds) 4. No security plugin is blocking the API endpoint For the Edge Function, you can reuse the WordPress proxy Edge Function from the WordPress integration (or the code in that tutorial) — no separate Edge Function is needed purely for Yoast. The yoast_head_json field is included in standard post and page responses automatically.
Pro tip: If yoast_head_json is present but most fields are empty or null, Yoast may not have been configured for that post type. Check Yoast SEO → Search Appearance → Content Types to ensure SEO features are enabled for your post type.
Expected result: The WordPress REST API response for /wp-json/wp/v2/posts includes a 'yoast_head_json' object with title, description, og_title, og_description, og_image, and schema fields populated.
Create the WordPress SEO proxy Edge Function
Create the WordPress SEO proxy Edge Function
The SEO proxy Edge Function fetches a WordPress post or page by slug and returns both the content fields and the yoast_head_json metadata. This is an extension of the general WordPress proxy pattern — if you have already built the wordpress-proxy Edge Function from the WordPress integration guide, you can either extend it or create a dedicated seo-focused function. For SEO-specific needs, it is useful to have a dedicated endpoint that always returns _embed=1 (for featured image), includes=yoast_head_json in the fields (which it does by default), and normalizes the Yoast data into a cleaner structure for React Helmet consumption. The normalization step extracts the most commonly needed SEO fields into a flat object rather than requiring the frontend to navigate the yoast_head_json tree. The Edge Function below fetches a post by slug and returns both the content and a normalized seoMeta object ready for React Helmet:
Create a Supabase Edge Function at supabase/functions/wordpress-seo/index.ts that fetches a WordPress post with Yoast SEO metadata. Read WP_SITE_URL from Deno.env.get(). Accept a POST request with 'type' ('posts' or 'pages') and 'slug' string. Call the WordPress REST API at /{type}?slug={slug}&_embed=1. Extract the first result's yoast_head_json object and normalize it into: metaTitle, metaDescription, canonicalUrl, ogTitle, ogDescription, ogImageUrl, twitterTitle, twitterDescription, twitterImageUrl, robots (object), schema (JSON-LD object). Return the full post data plus this seoMeta object.
Paste this in Lovable chat
1// supabase/functions/wordpress-seo/index.ts2const corsHeaders = {3 'Access-Control-Allow-Origin': '*',4 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',5};67interface YoastHeadJson {8 title?: string;9 description?: string;10 canonical?: string;11 og_title?: string;12 og_description?: string;13 og_image?: { url: string; width?: number; height?: number }[];14 twitter_title?: string;15 twitter_description?: string;16 twitter_image?: string;17 robots?: { index?: string; follow?: string };18 schema?: { '@graph'?: unknown[] };19}2021function normalizeYoastMeta(yoast: YoastHeadJson | null, fallbackTitle: string, fallbackUrl: string) {22 if (!yoast) return { metaTitle: fallbackTitle, canonicalUrl: fallbackUrl };23 return {24 metaTitle: yoast.title || fallbackTitle,25 metaDescription: yoast.description || '',26 canonicalUrl: yoast.canonical || fallbackUrl,27 ogTitle: yoast.og_title || yoast.title || fallbackTitle,28 ogDescription: yoast.og_description || yoast.description || '',29 ogImageUrl: yoast.og_image?.[0]?.url || '',30 twitterTitle: yoast.twitter_title || yoast.og_title || yoast.title || fallbackTitle,31 twitterDescription: yoast.twitter_description || yoast.og_description || yoast.description || '',32 twitterImageUrl: yoast.twitter_image || yoast.og_image?.[0]?.url || '',33 noIndex: yoast.robots?.index === 'noindex',34 schema: yoast.schema ? JSON.stringify(yoast.schema) : null,35 };36}3738Deno.serve(async (req) => {39 if (req.method === 'OPTIONS') return new Response('ok', { headers: corsHeaders });4041 try {42 const { type = 'posts', slug } = await req.json() as { type?: string; slug: string };4344 if (!slug) {45 return new Response(JSON.stringify({ error: 'slug is required' }), {46 status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' },47 });48 }4950 const siteUrl = Deno.env.get('WP_SITE_URL')!.replace(/\/$/, '');51 const url = `${siteUrl}/wp-json/wp/v2/${type}?slug=${encodeURIComponent(slug)}&_embed=1`;5253 const wpResponse = await fetch(url);54 if (!wpResponse.ok) {55 return new Response(JSON.stringify({ error: `WordPress API returned ${wpResponse.status}` }), {56 status: wpResponse.status, headers: { ...corsHeaders, 'Content-Type': 'application/json' },57 });58 }5960 const posts = await wpResponse.json();61 if (!Array.isArray(posts) || posts.length === 0) {62 return new Response(JSON.stringify({ error: 'Post not found', slug }), {63 status: 404, headers: { ...corsHeaders, 'Content-Type': 'application/json' },64 });65 }6667 const post = posts[0];68 const canonicalUrl = post.link || `${siteUrl}/${slug}/`;69 const seoMeta = normalizeYoastMeta(post.yoast_head_json || null, post.title?.rendered || slug, canonicalUrl);7071 return new Response(JSON.stringify({ post, seoMeta }), {72 headers: { ...corsHeaders, 'Content-Type': 'application/json' },73 });74 } catch (error) {75 console.error('wordpress-seo error:', error);76 return new Response(JSON.stringify({ error: String(error) }), {77 status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' },78 });79 }80});Pro tip: The Yoast SEO title field includes the site name suffix by default (e.g., 'Post Title - Site Name'). Use yoast_head_json.title directly as the full meta title — do not append the site name separately, as Yoast's template handles this.
Expected result: The wordpress-seo Edge Function returns a post object and a seoMeta object with metaTitle, metaDescription, ogImageUrl, and schema populated from Yoast's configuration.
Apply Yoast SEO metadata to React page head tags
Apply Yoast SEO metadata to React page head tags
With the SEO metadata available from the Edge Function, apply it to each page's head tags in your Lovable React app. React Helmet (or react-helmet-async for SSR compatibility) allows setting title, meta, link, and script tags from within React components dynamically. Install react-helmet-async via Lovable chat: ask Lovable to 'install react-helmet-async and set up the HelmetProvider at the root App component level'. Then create a SEO component that accepts the seoMeta object and renders the appropriate head tags. For JSON-LD schema (structured data), render it as a script tag with type='application/ld+json'. This is critical for rich results in Google Search — Yoast generates Article, BreadcrumbList, WebPage, and Organization schemas that help Google understand your content structure. Use the seoMeta.noIndex flag to conditionally add noindex/nofollow meta tags for pages Yoast has configured to be excluded from search engines (draft previews, paginated archives, tag pages). For a complete headless WordPress SEO implementation that matches what Yoast would produce on a traditionally rendered WordPress site, also set the canonical link tag (rel=canonical) to prevent duplicate content penalties.
Create a SEO component that applies Yoast SEO metadata to page head tags. Install and configure react-helmet-async in the project. The SEO component accepts props: metaTitle, metaDescription, canonicalUrl, ogTitle, ogDescription, ogImageUrl, twitterTitle, twitterDescription, schema (JSON-LD string), noIndex (boolean). Use Helmet to render: title tag, meta description, link rel=canonical, og:type/title/description/image, twitter:card/title/description/image, and if schema exists a script type=application/ld+json tag. Use this component on every post detail page. Use the wordpress-seo Edge Function to fetch seoMeta for each post slug and pass it to the SEO component.
Paste this in Lovable chat
Pro tip: Google's Structured Data Testing Tool (search.google.com/test/rich-results) can validate the JSON-LD schema output. Test your post pages after implementing the schema script tag to confirm Google can parse the Article structured data correctly.
Expected result: Post detail pages have correct meta title, meta description, Open Graph tags, and JSON-LD schema in the page head. Checking page source shows the Yoast-configured values in the meta tags. The Google Rich Results Test validates the schema.
Common use cases
Preserve Yoast SEO metadata in a headless WordPress migration
An existing WordPress site has thousands of posts with carefully configured Yoast SEO meta titles, descriptions, and schema. Migrating the frontend to Lovable must preserve all this SEO investment. The Edge Function fetches each post's yoast_head_json alongside content and the React frontend applies the metadata to every page route using React Helmet, maintaining search engine visibility.
Create a useSEO React hook that accepts a WordPress post slug. Call the wordpress-seo Edge Function to fetch the post including yoast_head_json. Extract yoast_head_json.title (meta title), yoast_head_json.description (meta description), yoast_head_json.og_image[0].url (OG image), and yoast_head_json.schema (JSON-LD). Use react-helmet-async to add these as head tags. Use this hook in every dynamic page component. Fall back to post.title if yoast_head_json is null.
Copy this prompt to try it in Lovable
Build an SEO audit tool using Yoast SEO scores
Yoast SEO Pro exposes content analysis scores — keyword density, readability score, cornerstone content flag, and SEO score — in the REST API. A Lovable app fetches all posts with their Yoast scores and displays an SEO audit dashboard showing which posts have poor meta descriptions, missing focus keywords, or failing readability scores, enabling editors to prioritize SEO improvements.
Build an SEO audit dashboard that fetches all WordPress posts via the wordpress-seo Edge Function. For each post, display: post title, Yoast SEO score rating (green/orange/red from yoast_head_json), meta description length (should be 120-155 chars), Open Graph image present (yes/no). Sort by Yoast score ascending to show worst-performing posts first. Add a link to edit each post in WordPress admin.
Copy this prompt to try it in Lovable
Implement dynamic Open Graph images for social sharing
When shared on social media, posts need accurate Open Graph images, titles, and descriptions. The Lovable app fetches Yoast SEO's og_image, og_title, and og_description for each post and uses them in the page's OG head tags. Posts without a custom OG image fall back to the post's featured image. This ensures social media preview cards show correct, editor-configured content for every post.
Add social sharing meta tags to all post detail pages using Yoast SEO data. When rendering /blog/:slug, call the wordpress-seo Edge Function to get the post and its yoast_head_json. Use react-helmet-async to set: og:title from yoast_head_json.og_title, og:description from yoast_head_json.og_description, og:image from yoast_head_json.og_image[0].url (fallback to post.featured_image.source_url), twitter:card as 'summary_large_image', twitter:title and twitter:description from the Yoast Twitter fields.
Copy this prompt to try it in Lovable
Troubleshooting
yoast_head_json is missing from WordPress REST API responses
Cause: Yoast SEO is not installed, is version 13.x or earlier (which did not include yoast_head_json), or the Yoast REST API integration is disabled.
Solution: Update Yoast SEO to version 14.0 or newer in WordPress Admin → Dashboard → Updates. Confirm Yoast is active in Plugins → Installed Plugins. In Yoast SEO → General → Features, check that the REST API feature is enabled (it is enabled by default since v14).
og_image is null or missing even when posts have featured images
Cause: Yoast SEO does not automatically use the WordPress featured image as the OG image unless you have configured it in Yoast settings or the post has a custom OG image set.
Solution: In WordPress Admin → Yoast SEO → Search Appearance → Content Types → Posts, under 'Image to use for social sharing', select 'Featured image'. This configures Yoast to automatically use the post's featured image as the OG image for all posts without a manually set OG image. Alternatively, in your Edge Function, fall back to _embedded['wp:featuredmedia'][0].source_url when og_image is empty.
1// Fallback OG image to featured image when Yoast og_image is empty2const ogImageUrl = yoast?.og_image?.[0]?.url3 || post._embedded?.['wp:featuredmedia']?.[0]?.source_url4 || '';JSON-LD schema renders but Google Search Console shows errors in rich results
Cause: The JSON-LD schema string in yoast_head_json.schema contains escaped characters that get double-escaped when re-serialized, or the schema references URLs that use the old WordPress domain rather than the new Lovable app domain.
Solution: Log the raw yoast_head_json.schema object to Cloud → Logs and compare it with what your frontend renders. The schema JSON must be the original parsed object re-serialized with JSON.stringify, not a string that has been parsed and re-stringified multiple times. Also check if the schema contains inLanguage or url properties pointing to the WordPress domain — these may need to be updated to match your Lovable app's domain.
1// Correct: serialize the schema object once2<script type="application/ld+json">3 {seoMeta.schema} {/* schema is already a JSON string from the Edge Function */}4</script>Best practices
- Use yoast_head_json.title directly as the full page meta title — Yoast applies its title template (including site name suffix) before storing the value, so do not append the site name separately or it will be duplicated.
- Always fall back to post.title.rendered when yoast_head_json.title is empty — some older posts may not have Yoast metadata configured, and a missing meta title is worse for SEO than a simple fallback.
- Set the canonical URL from yoast_head_json.canonical rather than constructing it from the URL path — Yoast may configure non-obvious canonical URLs for posts with multiple access paths.
- Include the JSON-LD schema from yoast_head_json.schema on every post detail page — Google uses Article structured data to enhance search result presentation with rich snippets.
- Handle the noIndex flag from yoast.robots.index === 'noindex' — Yoast marks some pages as noindex for legitimate reasons (paginated archives, tag archives, etc.) and respecting this in the headless frontend preserves the editorial SEO decisions.
- Test social sharing previews after implementing OG tags using Facebook Sharing Debugger (developers.facebook.com/tools/debug) and Twitter Card Validator — these tools show exactly what will appear in social shares and are the best way to catch missing or malformed meta tags.
- For the Yoast breadcrumb schema, update the URL values from the WordPress domain to the Lovable app domain — the schema graph includes BreadcrumbList with urls pointing to the source WordPress installation, which need updating for the headless frontend.
Alternatives
The general WordPress integration covers all post content — this Yoast-specific integration focuses on SEO metadata extraction, which is an additive layer on top of the WordPress content integration.
Choose Ghost if you want a publishing platform with built-in SEO fields (meta_title, meta_description, og_image) without needing a separate SEO plugin — Ghost includes these fields natively in its Content API.
Choose Ahrefs API if you need programmatic access to external SEO metrics (domain authority, backlink count, keyword rankings) rather than Yoast's on-page meta tag management.
Frequently asked questions
Does Yoast SEO Free include yoast_head_json in the REST API?
Yes. Yoast SEO Free has included the yoast_head_json object in WordPress REST API responses since version 14.0 (released in 2020). You do not need Yoast SEO Premium to access this data. All fields including meta title, meta description, Open Graph tags, Twitter card data, robots directives, and the full JSON-LD schema graph are available in the free version.
Will Google index my headless Lovable app correctly with these meta tags?
Yes, if implemented correctly. Google's crawlers support client-rendered JavaScript applications and can read meta tags injected by React Helmet. The critical requirement is that meta tags are present in the page when Google's Chromium-based crawler renders it, which happens with React Helmet's dynamic head management. Test each page type in Google Search Console's URL Inspection tool after deploying to confirm Google is seeing the correct meta tags.
How do I handle Yoast SEO configuration for the WordPress home page in a headless setup?
The WordPress home page Yoast configuration (Settings → Yoast SEO → Search Appearance → General) is not a standard post or page — it is a site-level SEO configuration. Fetch it using the Yoast REST API endpoint: /wp-json/yoast/v1/get_head?url={home_url}. This endpoint is available when the Yoast REST API integration is enabled and returns the full yoast_head_json for any URL including the home page and archive pages.
What should I do if some posts have Yoast data and others do not?
Always implement fallbacks. If yoast_head_json is null or its fields are empty, fall back to the WordPress post's own title (post.title.rendered), excerpt (post.excerpt.rendered stripped of HTML), and featured image. This ensures every page has at minimum a reasonable meta title and description even for old posts that were published before Yoast was installed or configured on the WordPress site.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation