{"id":266611,"date":"2026-10-12T10:18:32","date_gmt":"2026-10-12T01:18:32","guid":{"rendered":"https:\/\/designcopy.net\/en\/?p=266611"},"modified":"2026-10-12T10:18:32","modified_gmt":"2026-10-12T01:18:32","slug":"structured-outputs-claude-vs-openai-vs-gemini-seo-metadata-json-2026","status":"publish","type":"post","link":"https:\/\/designcopy.net\/en\/structured-outputs-claude-vs-openai-vs-gemini-seo-metadata-json-2026\/","title":{"rendered":"Structured Outputs: Claude vs OpenAI vs Gemini for SEO JSON"},"content":{"rendered":"<p><title>Structured Outputs: <a href=\"https:\/\/en.wikipedia.org\/wiki\/Claude_(language_model)\" target=\"_blank\" rel=\"noopener nofollow external noreferrer\" data-wpel-link=\"external\">Claude<\/a> vs <a href=\"https:\/\/openai.com\/\" target=\"_blank\" rel=\"noopener nofollow external noreferrer\" data-wpel-link=\"external\">OpenAI<\/a> vs Gemini for SEO JSON<\/title><\/p>\n<p class=\"updated\">Last updated: October 2026<\/p>\n<div style=\"background:#f3e5f5;border:2px solid #9c27b0;padding:20px;margin:0 0 24px 0;border-radius:8px;\">\n<strong style=\"color:#6a1b9a;font-size:1.1em;\">Quick Answer:<\/strong><\/p>\n<ul style=\"margin:10px 0 0 0;padding-left:20px;line-height:1.8;\">\n<li><strong>All three providers now enforce a JSON schema<\/strong>: Claude through <code>output_config.format<\/code>, OpenAI through <code>json_schema<\/code> with <code>strict: true<\/code>, Gemini through a <code>response_format<\/code> schema.<\/li>\n<li><strong>Claude rejects length constraints<\/strong>: minLength, maxLength, minimum and maximum are unsupported, so a 60-character title limit needs a code check.<\/li>\n<li><strong>Gemini supports minimum, maximum, minItems and maxItems<\/strong>, which makes it the only one of the three that can bound numeric scores and list sizes in the schema itself.<\/li>\n<li><strong>A valid schema does not mean a valid answer<\/strong>: a refusal or a max_tokens cut-off can return HTTP 200 with output that does not match.<\/li>\n<\/ul>\n<\/div>\n<p>An SEO pipeline that writes title tags, meta descriptions, FAQ schema and internal link suggestions needs JSON it can feed straight into WordPress or Rank Math.<\/p>\n<p>Free-form prompts that say &#8220;respond only in JSON&#8221; fail on roughly the schedule you would expect from a language model: rarely, and always on the batch you were not watching.<\/p>\n<h2>How Do You Switch On Structured Outputs on Each Provider?<\/h2>\n<p>On Claude you set <code>output_config.format.type<\/code> to <code>json_schema<\/code> and pass the schema. The Python SDK wraps this as <code>client.messages.parse(output_format=YourModel)<\/code>, per <a href=\"https:\/\/platform.claude.com\/docs\/en\/docs\/build-with-claude\/structured-outputs\" target=\"_blank\" rel=\"noopener nofollow external noreferrer\" data-wpel-link=\"external\">Anthropic&#8217;s structured outputs documentation<\/a>. It lists Claude Sonnet 5.5, Opus 5.5 and Haiku 4.5 among supported models.<\/p>\n<p>On OpenAI you pass a <code>json_schema<\/code> response format with <code>strict: true<\/code>. <a href=\"https:\/\/developers.openai.com\/api\/docs\/guides\/structured-outputs\" target=\"_blank\" rel=\"noopener nofollow external noreferrer\" data-wpel-link=\"external\">OpenAI&#8217;s structured outputs guide<\/a> lists gpt-4o-mini and gpt-4o-2024-08-06 and later as supported.<\/p>\n<p>On Gemini you set a <code>response_format<\/code> with <code>mime_type<\/code> of <code>application\/json<\/code> and a schema, per <a href=\"https:\/\/ai.google.dev\/gemini-api\/docs\/structured-output\" target=\"_blank\" rel=\"noopener nofollow external noreferrer\" data-wpel-link=\"external\">Google&#8217;s Gemini structured output documentation<\/a>. The page names Gemini 3.8 Flash and Gemini 3.1 Pro Preview.<\/p>\n<div style=\"background:#e8f5e9;border-left:4px solid #4caf50;padding:16px;margin:20px 0;\">\n<strong style=\"color:#2e7d32;\">Pro Tip:<\/strong><\/p>\n<p style=\"margin:8px 0 0 0;\">Define the schema once as a Pydantic or Zod model and generate the provider-specific JSON from it. Hand-written schemas drift apart across three providers within a week.<\/p>\n<\/div>\n<figure style=\"margin:24px 0;text-align:center;\"><img decoding=\"async\" src=\"https:\/\/designcopy.net\/wp-content\/uploads\/2026\/10\/structured-outputs-claude-vs-openai-vs-gemini-seo-metadata-json-2026-internal-1-hero.jpg\" alt=\"How Do You Switch On Structured Outputs on Each Provider?\" style=\"max-width:100%;height:auto;border-radius:8px;\" loading=\"lazy\" title=\"\"><\/figure>\n<h2>Which Schema Keywords Survive on Each Provider?<\/h2>\n<p>This is where pipelines break. A schema that validates in your editor can be rejected by the API, or silently stripped of the constraint you cared about.<\/p>\n<table style=\"width:100%;border-collapse:collapse;margin:20px 0;\">\n<thead>\n<tr style=\"background:#1a237e;color:#fff;\">\n<th style=\"padding:10px;text-align:left;\">Keyword<\/th>\n<th style=\"padding:10px;text-align:left;\">Claude<\/th>\n<th style=\"padding:10px;text-align:left;\">Gemini<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr style=\"border-bottom:1px solid #e2e8f0;\">\n<td style=\"padding:10px;\">minLength \/ maxLength<\/td>\n<td style=\"padding:10px;\">Not supported<\/td>\n<td style=\"padding:10px;\">Not listed<\/td>\n<\/tr>\n<tr style=\"border-bottom:1px solid #e2e8f0;\">\n<td style=\"padding:10px;\">minimum \/ maximum<\/td>\n<td style=\"padding:10px;\">Not supported<\/td>\n<td style=\"padding:10px;\">Supported<\/td>\n<\/tr>\n<tr style=\"border-bottom:1px solid #e2e8f0;\">\n<td style=\"padding:10px;\">minItems \/ maxItems<\/td>\n<td style=\"padding:10px;\">minItems of 0 or 1 only<\/td>\n<td style=\"padding:10px;\">Both supported<\/td>\n<\/tr>\n<tr style=\"border-bottom:1px solid #e2e8f0;\">\n<td style=\"padding:10px;\">additionalProperties<\/td>\n<td style=\"padding:10px;\">Must be false<\/td>\n<td style=\"padding:10px;\">Supported<\/td>\n<\/tr>\n<tr style=\"border-bottom:1px solid #e2e8f0;\">\n<td style=\"padding:10px;\">Recursive schemas<\/td>\n<td style=\"padding:10px;\">Not supported<\/td>\n<td style=\"padding:10px;\">Not stated; deep nesting may be rejected<\/td>\n<\/tr>\n<tr>\n<td style=\"padding:10px;\">enum<\/td>\n<td style=\"padding:10px;\">Strings, numbers, bools, nulls<\/td>\n<td style=\"padding:10px;\">Strings and numbers<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>OpenAI requires every field to be declared as required and <code>additionalProperties<\/code> set to false, per its guide. The table omits OpenAI because the page does not spell out the full keyword list, and a half-filled column would mislead.<\/p>\n<figure style=\"margin:24px 0;text-align:center;\"><img decoding=\"async\" src=\"https:\/\/designcopy.net\/wp-content\/uploads\/2026\/10\/structured-outputs-claude-vs-openai-vs-gemini-seo-metadata-json-2026-internal-2-hero.jpg\" alt=\"Which Schema Keywords Survive on Each Provider?\" style=\"max-width:100%;height:auto;border-radius:8px;\" loading=\"lazy\" title=\"\"><\/figure>\n<h2>Why Can a Claude Schema Not Cap a Meta Description at 155 Characters?<\/h2>\n<p>Because maxLength is on the unsupported list. The model is told the shape, not the length, so a description field can come back at 170 characters and still be &#8220;valid&#8221;.<\/p>\n<p>The workable pattern has three parts. Write the limit into the field description (&#8220;at most 155 characters&#8221;). Validate length in code after the call. Retry once with the over-length value quoted back to the model.<\/p>\n<p>Claude may also return enum values that differ from your list only in capitalisation, per <a href=\"https:\/\/platform.claude.com\/docs\/en\/docs\/build-with-claude\/structured-outputs\" target=\"_blank\" rel=\"noopener nofollow external noreferrer\" data-wpel-link=\"external\">Anthropic&#8217;s structured outputs documentation<\/a>. If your <code>search_intent<\/code> enum is informational, commercial, transactional, compare case-insensitively before writing to your database.<\/p>\n<div style=\"background:#fff3e0;border-left:4px solid #ff9800;padding:16px;margin:20px 0;\">\n<strong style=\"color:#e65100;\">Warning:<\/strong><\/p>\n<p style=\"margin:8px 0 0 0;\">Claude schemas have complexity limits: 24 optional parameters and 16 union-typed parameters across all strict schemas in a request. Exceeding them returns a 400 &#8220;Schema is too complex for compilation&#8221;. A single mega-schema for a whole article will hit that.<\/p>\n<\/div>\n<figure style=\"margin:24px 0;text-align:center;\"><img decoding=\"async\" src=\"https:\/\/designcopy.net\/wp-content\/uploads\/2026\/10\/structured-outputs-claude-vs-openai-vs-gemini-seo-metadata-json-2026-internal-3-hero.jpg\" alt=\"Why Can a Claude Schema Not Cap a Meta Description at 155 Characters?\" style=\"max-width:100%;height:auto;border-radius:8px;\" loading=\"lazy\" title=\"\"><\/figure>\n<h2>What Happens When the Output Is Cut Off or Refused?<\/h2>\n<p>The guarantee has two holes, and both return HTTP 200. When Claude stops with <code>stop_reason: \"refusal\"<\/code> or <code>\"max_tokens\"<\/code>, the output may not match your schema.<\/p>\n<p>A FAQ block with eight questions can hit a low <code>max_tokens<\/code> halfway through the sixth answer. The JSON is truncated, your parser throws, and the batch run records a failure that looks like a model problem.<\/p>\n<p>OpenAI surfaces refusals as a separate <code>refusal<\/code> field instead of schema content, which is easier to branch on. Either way, read the stop signal before you parse.<\/p>\n<div style=\"background:#e8f5e9;border-left:4px solid #4caf50;padding:16px;margin:20px 0;\">\n<strong style=\"color:#2e7d32;\">Pro Tip:<\/strong><\/p>\n<p style=\"margin:8px 0 0 0;\">Set max_tokens to at least twice the expected JSON size, and treat any stop reason other than a normal end-of-turn as a failed call that gets retried, not parsed.<\/p>\n<\/div>\n<h2>How Do Structured Outputs Interact With Cost and Caching?<\/h2>\n<p>Claude injects an extra system prompt describing the format, so input tokens run slightly higher, per <a href=\"https:\/\/platform.claude.com\/docs\/en\/docs\/build-with-claude\/structured-outputs\" target=\"_blank\" rel=\"noopener nofollow external noreferrer\" data-wpel-link=\"external\">Anthropic&#8217;s structured outputs documentation<\/a>. The first call with a new schema also pays a grammar compile delay.<\/p>\n<p>The compiled grammar is cached for 24 hours from last use. Changing the schema structure invalidates it, while changing a name or description does not.<\/p>\n<p>The bigger effect is on prompt caching. Changing <code>output_config.format<\/code> invalidates the prompt cache for that thread. Our comparison of <a href=\"\/en\/prompt-caching-claude-vs-openai-vs-gemini-seo-pipeline-cost-2026\/\" data-wpel-link=\"internal\" rel=\"follow noopener noreferrer\" class=\"wpel-icon-right\">prompt caching on Claude, OpenAI and Gemini<i class=\"wpel-icon dashicons-before dashicons-admin-page\" aria-hidden=\"true\"><\/i><\/a> covers why a stable prefix matters.<\/p>\n<blockquote style=\"border-left:4px solid #9e9e9e;background:#f5f5f5;margin:20px 0;padding:14px 18px;\">\n<p style=\"margin:0;\">JSON mode only guarantees valid JSON syntax; structured outputs guarantee the response follows your schema.<\/p>\n<p style=\"margin:8px 0 0 0;\">&#8211; Per OpenAI&#8217;s published structured outputs guide<\/p>\n<\/blockquote>\n<div style=\"background:#e3f2fd;border:2px solid #1976d2;padding:20px;margin:20px 0;border-radius:8px;\">\n<strong style=\"color:#0d47a1;\">Key Takeaway:<\/strong><\/p>\n<p style=\"margin:8px 0 0 0;\">Use structured outputs for shape and a code validator for limits. Gemini can bound numbers and list sizes in the schema; Claude cannot bound strings or numbers at all.<\/p>\n<p style=\"margin:8px 0 0 0;\">Check the stop reason before parsing, keep one schema per stage, and expect a slower first call.<\/p>\n<\/div>\n<h2>Frequently Asked Questions<\/h2>\n<div style=\"border-bottom:1px solid #e2e8f0;padding:16px 0;\">\n<h3>Is JSON mode the same as structured outputs?<\/h3>\n<p>No. <a href=\"https:\/\/developers.openai.com\/api\/docs\/guides\/structured-outputs\" target=\"_blank\" rel=\"noopener nofollow external noreferrer\" data-wpel-link=\"external\">OpenAI&#8217;s structured outputs guide<\/a> explains that JSON mode only guarantees valid JSON syntax, while structured outputs guarantee the response matches your schema.<\/p>\n<\/div>\n<div style=\"border-bottom:1px solid #e2e8f0;padding:16px 0;\">\n<h3>Can I enforce a 60-character title limit in the schema?<\/h3>\n<p>Not on Claude. <a href=\"https:\/\/platform.claude.com\/docs\/en\/docs\/build-with-claude\/structured-outputs\" target=\"_blank\" rel=\"noopener nofollow external noreferrer\" data-wpel-link=\"external\">Anthropic&#8217;s structured outputs documentation<\/a> lists minLength and maxLength as unsupported. Put the limit in the field description and check the length in code after the call.<\/p>\n<\/div>\n<div style=\"border-bottom:1px solid #e2e8f0;padding:16px 0;\">\n<h3>What happens if the model refuses or runs out of tokens mid-JSON?<\/h3>\n<p>On Claude the response still returns HTTP 200, but with stop_reason refusal or max_tokens the output may not match the schema, per <a href=\"https:\/\/platform.claude.com\/docs\/en\/docs\/build-with-claude\/structured-outputs\" target=\"_blank\" rel=\"noopener nofollow external noreferrer\" data-wpel-link=\"external\">Anthropic&#8217;s structured outputs documentation<\/a>. Check stop_reason before parsing. OpenAI returns a separate refusal field instead.<\/p>\n<\/div>\n<div style=\"border-bottom:1px solid #e2e8f0;padding:16px 0;\">\n<h3>Why is the first call with a new schema slower?<\/h3>\n<p>Both <a href=\"https:\/\/www.anthropic.com\/\" target=\"_blank\" rel=\"noopener nofollow external noreferrer\" data-wpel-link=\"external\">Anthropic<\/a> and OpenAI compile the schema on first use. Anthropic caches the compiled grammar for 24 hours from last use, so a daily batch pays the compile cost once.<\/p>\n<\/div>\n<div style=\"border-bottom:1px solid #e2e8f0;padding:16px 0;\">\n<h3>Will changing my schema break prompt caching on Claude?<\/h3>\n<p>Yes for that conversation thread. <a href=\"https:\/\/platform.claude.com\/docs\/en\/docs\/build-with-claude\/structured-outputs\" target=\"_blank\" rel=\"noopener nofollow external noreferrer\" data-wpel-link=\"external\">Anthropic&#8217;s structured outputs documentation<\/a> states that changing the output format invalidates the prompt cache, so keep one schema per pipeline stage.<\/p>\n<\/div>\n<hr \/>\n<p><em>DesignCopy Editorial Team<\/em><\/p>\n<p><script type=\"application\/ld+json\">\n[{\"@context\": \"https:\/\/schema.org\", \"@type\": \"Article\", \"headline\": \"Structured Outputs: Claude vs OpenAI vs Gemini for SEO JSON\", \"description\": \"How structured outputs differ on Claude, OpenAI and Gemini for SEO metadata JSON: supported schema keywords, length limits, refusals, truncation and caching effects.\", \"datePublished\": \"2026-10-09\", \"dateModified\": \"2026-10-09\", \"author\": {\"@type\": \"Organization\", \"name\": \"DesignCopy Editorial Team\", \"url\": \"https:\/\/designcopy.net\"}, \"publisher\": {\"@type\": \"Organization\", \"name\": \"DesignCopy\", \"url\": \"https:\/\/designcopy.net\"}}, {\"@context\": \"https:\/\/schema.org\", \"@type\": \"FAQPage\", \"mainEntity\": [{\"@type\": \"Question\", \"name\": \"Is JSON mode the same as structured outputs?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"No. OpenAI's structured outputs guide explains that JSON mode only guarantees valid JSON syntax, while structured outputs guarantee the response matches your schema.\"}}, {\"@type\": \"Question\", \"name\": \"Can I enforce a 60-character title limit in the schema?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Not on Claude. Anthropic's structured outputs documentation lists minLength and maxLength as unsupported. Put the limit in the field description and check the length in code after the call.\"}}, {\"@type\": \"Question\", \"name\": \"What happens if the model refuses or runs out of tokens mid-JSON?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"On Claude the response still returns HTTP 200, but with stop_reason refusal or max_tokens the output may not match the schema, per Anthropic's structured outputs documentation. Check stop_reason before parsing. OpenAI returns a separate refusal field instead.\"}}, {\"@type\": \"Question\", \"name\": \"Why is the first call with a new schema slower?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Both Anthropic and OpenAI compile the schema on first use. Anthropic caches the compiled grammar for 24 hours from last use, so a daily batch pays the compile cost once.\"}}, {\"@type\": \"Question\", \"name\": \"Will changing my schema break prompt caching on Claude?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Yes for that conversation thread. Anthropic's structured outputs documentation states that changing the output format invalidates the prompt cache, so keep one schema per pipeline stage.\"}}]}]\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>An SEO pipeline that writes title tags, meta descriptions, FAQ schema and internal link suggestions needs JSON it can feed straight into WordPress or Rank Math.<\/p>\n","protected":false},"author":1,"featured_media":266622,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","rank_math_title":"","rank_math_description":"","rank_math_focus_keyword":"","footnotes":""},"categories":[1462],"tags":[],"class_list":["post-266611","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-learning-center","et-has-post-format-content","et_post_format-et-post-format-standard"],"_links":{"self":[{"href":"https:\/\/designcopy.net\/en\/wp-json\/wp\/v2\/posts\/266611","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/designcopy.net\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/designcopy.net\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/designcopy.net\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/designcopy.net\/en\/wp-json\/wp\/v2\/comments?post=266611"}],"version-history":[{"count":1,"href":"https:\/\/designcopy.net\/en\/wp-json\/wp\/v2\/posts\/266611\/revisions"}],"predecessor-version":[{"id":266616,"href":"https:\/\/designcopy.net\/en\/wp-json\/wp\/v2\/posts\/266611\/revisions\/266616"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/designcopy.net\/en\/wp-json\/wp\/v2\/media\/266622"}],"wp:attachment":[{"href":"https:\/\/designcopy.net\/en\/wp-json\/wp\/v2\/media?parent=266611"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/designcopy.net\/en\/wp-json\/wp\/v2\/categories?post=266611"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/designcopy.net\/en\/wp-json\/wp\/v2\/tags?post=266611"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}