Generating SEO titles and meta descriptions at scale with AI in n8n
Published 14 August 2026 · 6 min read
A technical SEO audit almost always turns up the same thing: dozens, sometimes hundreds, of pages with no meta description, or with a <title> tag that gets truncated in search results because it runs past 60 characters. Fixing them one by one in the CMS editor takes hours on a mid-sized site — and this is exactly the kind of repetitive task, bounded by clear rules (length, uniqueness, keyword presence), that n8n can automate end to end: find the affected pages, generate a unique title and meta description with AI, check they're compliant, then republish them without ever opening the editor.
This isn't just a matter of convenience. A landmark information-retrieval study, Tombros and Sanderson (SIGIR, 1998) — see on Google Scholar, found that summaries built around a user's actual information need (so-called "query-biased" summaries) let people judge a document's relevance far faster and more accurately than a generic summary made of the title plus the first few sentences. That's exactly what separates a good meta description from a bad one: a generic sentence mechanically pulled from the first paragraph converts worse than a synthesis that directly answers the search intent the page targets — which is precisely what this workflow asks the LLM to produce.
Pipeline overview
The workflow has five steps: finding the pages that need fixing, extracting each page's content, generating the title and meta description with a structured-output LLM, a quality check, then republishing via the CMS's REST API.
Sitemap / page list → Extract content + current tags → Filter (missing / out of range) → LLM (title + meta) → Quality check → IF (ok / needs review) → Publish via API
Step 1 — Finding the pages that need fixing
Two sources let you list a site's pages: the sitemap.xml (an HTTP Request node followed by XML to extract the list of URLs), or, for a WordPress site, the native REST API (GET /wp-json/wp/v2/posts?per_page=100), which directly returns content IDs. The second option is preferable once you need to republish afterward, since it gives you the post ID needed for the write.
For each URL, an HTTP Request node fetches the page's HTML, then a Code node extracts the <title> tag and the <meta name="description"> content with a regular expression:
const html = $json.data;
const title = (html.match(/<title>(.*?)<\/title>/i) || [])[1] || "";
const metaMatch = html.match(/<meta\s+name=["']description["']\s+content=["']([^"']*)["']/i);
const description = metaMatch ? metaMatch[1] : "";
return [{
json: {
url: $json.url,
currentTitle: title.trim(),
currentMeta: description.trim(),
needsFix: !description || description.length < 70 || description.length > 160 || title.length > 60,
},
}];
A Filter node then keeps only the rows where needsFix is true: pages with no meta description, a meta description too short to be informative, a meta description that gets truncated in search results, or a title that's already too long. A meta description that's already present and well-sized is never touched — the workflow only targets what genuinely needs fixing.
Step 2 — Extracting useful content from the page
The LLM needs more than the URL to produce something relevant: a Code node (or the native HTML Extract node in n8n) isolates the H1 and the first two or three body paragraphs, excluding the menu, footer, and navigation blocks. This context — not the title alone — is what lets the model produce a synthesis that's genuinely oriented toward what the page actually delivers, the same explicit-context principle covered in our guide to AI-generated product listings and our Information Extractor guide.
Step 3 — Generating with structured output
A Chain LLM node (see our guides to connecting OpenAI or Claude and GPT to n8n) receives the H1, the content excerpt, and the URL, with a prompt that sets strict length constraints and bans generic filler ("Discover...", "Click here..."). A Structured Output Parser node forces the response into a fixed schema, as in our dedicated guide:
{
"seo_title": "string, max 60 characters",
"meta_description": "string, 150-160 characters, must include the page's main topic"
}
The prompt benefits from explicitly stating the target keyword or search intent when it's known (for example, pulled from a Google Search Console export): that's the lever that pushes the result closer to a "query-biased" summary rather than a plain generic summary of the content.
Step 4 — Quality check before publishing
A Code node systematically checks the LLM's output before anything is sent to the CMS:
const d = $json;
const issues = [];
if (d.meta_description.length < 120 || d.meta_description.length > 160) {
issues.push("meta length out of range");
}
if (d.seo_title.length > 60) issues.push("title too long");
if (/discover|click here|don't hesitate/i.test(d.meta_description)) {
issues.push("generic filler detected");
}
return [{ json: { ...d, ok: issues.length === 0, issues } }];
An IF node then splits compliant pages (direct publication) from pages that need review (routed to a human queue instead of being blocked outright). For the first runs, the human approval with Wait and Slack pattern lets you validate a sample before rolling it out to the whole site.
Step 5 — Republishing via the REST API
This is the most CMS-specific step. On WordPress with Yoast SEO, the REST API exposes these fields as read-only by default — a POST to /wp-json/wp/v2/posts/{id} with Yoast fields in the request body simply has no effect. Two options make the write possible:
- Add a short PHP snippet on the WordPress side that calls
register_post_meta()withshow_in_rest: truefor the_yoast_wpseo_titleand_yoast_wpseo_metadescfields, which makes them writable through the standard posts endpoint. - Use a dedicated plugin that exposes a specific write endpoint for these fields, if you'd rather not touch theme or plugin code.
RankMath follows the same logic with its own metadata keys. Once either option is in place, an authenticated HTTP Request node (Basic Auth with a WordPress application password, or an OAuth2 credential depending on your setup) is enough to write the generated title and meta description, mapping each field explicitly rather than overwriting the whole post object.
| Generated field | WordPress + Yoast destination | RankMath destination |
|---|---|---|
seo_title |
_yoast_wpseo_title |
rank_math_title |
meta_description |
_yoast_wpseo_metadesc |
rank_math_description |
For a site on a different platform (Webflow, Shopify), the principle stays the same — target whatever SEO field the CMS's API exposes. Our Shopify and Webflow guides cover the matching authentication.
Processing the site in batches, not in one pass
On a site with several hundred pages, a Loop Over Items node processes URLs in batches of 20 to 50, with a short Wait between batches to stay under both the LLM API's and WordPress's rate limits. This pattern is covered in our guide to n8n loops and our guide to API rate limits; it also avoids firing off hundreds of LLM calls at once that would be hard to audit if the prompt turns out to have an issue.
Tracking impact and avoiding duplicates
Every run benefits from being logged — URL processed, old and new values, date — into a Supabase table or a Google Sheet, following the same logging principle as our guide to a GDPR audit trail with Supabase. This log serves two purposes: never reprocessing a page that was already fixed in the last 30 days, and cross-referencing the click-through variations later observed in the weekly Search Console SEO report against the exact date of each tag change.
Summary
Automating title and meta description generation in n8n rests on four guardrails: targeting only genuinely problematic pages rather than rewriting everything, feeding the LLM the page's actual content rather than just a title, enforcing structured output with strict length bounds, and logging every change so its effect can be measured. That same foundation — structured extraction, constrained generation, quality control, logging — is what powers the reporting workflows in the Compliance & Audit Pack, built to turn raw data into reliable actions without constant human supervision.
FAQ
Frequently asked questions
Does the WordPress REST API let you edit Yoast SEO fields directly?
No, not by default: Yoast exposes its fields as read-only in the standard REST API. To make them writable, you either add a short PHP snippet that calls register_post_meta with show_in_rest set to true for each Yoast field, or use a dedicated plugin (such as Yoast SEO API Manager) that exposes a write endpoint. RankMath follows the same logic with its own metadata fields.
How many pages can you process per run without getting rate-limited?
This mostly depends on the LLM API's rate limit and WordPress's, not on any limit from n8n. A batch of 20 to 50 pages per run, with a short delay between calls, runs fine on nearly every hosting setup and API plan. For a site with several thousand pages, it's better to spread processing across multiple runs than to aim for full coverage in one pass.
Could the workflow overwrite meta descriptions that were already optimized manually?
No, as long as the upstream filter is set correctly: only target pages whose meta description is missing, or whose length is clearly out of the recommended range (under 70 or over 160 characters). A meta description that's already present and within range is never touched by the workflow, unless you explicitly force a full regeneration.
Should every generated title and meta description be reviewed before publishing?
For the first runs, or on a high-traffic site, yes: routing results to a human review queue instead of direct publication lets you calibrate the prompt without risk. Once tone and length are stable on a sample, automatic publication with an upstream quality check becomes reliable for the rest of the site.
Bundle FlowKit Complet
€269