Prompt to Get Structured JSON You Can Actually Parse
The Parsing Problem
A meal-planning app team wants to let users paste any recipe and get back structured data: ingredients, quantities, units, steps, and timing. The first version asked ChatGPT to “return the recipe as JSON,” and it worked about half the time. The other half, the model wrapped the JSON in a friendly sentence, added a trailing comment, switched a field to a string, or used smart quotes that broke the parser. The app crashed on real user input, and the team blamed the model. The model was fine. The prompt never pinned the schema or the output contract.
Getting parseable JSON is a formatting problem with a formatting solution. Below is one prompt that reliably returns strict JSON for a recipe, the fields you swap for your own data shape, the output to expect, and the schema variations that keep a pipeline stable as your needs change.
The JSON Prompt
Paste the block as a single message. The schema and the output contract are what stop the model from decorating your data.
You are a data extraction service. Convert a recipe into strict JSON for a meal-planning app.
Recipe text:
{{RECIPE_TEXT}}
Return exactly one JSON object that matches this schema:
{
"title": string,
"servings": integer,
"prep_minutes": integer,
"cook_minutes": integer,
"ingredients": [
{"name": string, "quantity": number, "unit": string, "note": string}
],
"steps": [string],
"tags": [string]
}
Rules:
1. Output raw JSON only. No markdown code fences, no explanation, no trailing text.
2. Use double quotes for every key and string. Never use smart quotes.
3. If a numeric field is missing, use null, never a guessed number.
4. Keep units lowercase and singular, for example "cup", "gram", "clove".
5. Put any prep detail such as "finely chopped" in the note field, not in name.
6. Derive tags only from the recipe content, maximum five.
7. If the text is not a recipe, return {"error": "not_a_recipe"}.
8. Do not invent ingredients that are not in the text.
Rule one is doing more work than any other line. The single most common failure is not bad data; it is good data wrapped in a sentence or a code fence, which is valid for a human and fatal for a parser. Naming that explicitly removes the default chat behavior.
Replacements to Make
| Token | What to enter | Example |
|---|---|---|
| {{RECIPE_TEXT}} | The raw input to parse | A pasted blog recipe with a story intro |
| schema fields | Your app’s data shape | Add “cuisine” or drop “tags” |
| unit style | How you normalize units | lowercase singular, or metric-only |
| error case | Behavior on bad input | Return an error object instead of guessing |
| tags limit | How many labels you allow | Three for a tight UI, five for search |
Two choices pay off. Setting the unit style once means your app never has to reconcile “Tbsp” against “tablespoon.” And defining the error case up front stops the model from inventing a plausible recipe when the input is junk, which is the failure that silently corrupts a dataset.
The JSON You Should Get
Expect a single raw object with no wrapper. A trimmed slice of the expected shape:
{
"title": "Lemon Garlic Roast Chicken",
"servings": 4,
"prep_minutes": 15,
"cook_minutes": 60,
"ingredients": [
{"name": "chicken", "quantity": 1.8, "unit": "kilogram", "note": "whole"},
{"name": "lemon", "quantity": 2, "unit": "unit", "note": "one zested, both halved"},
{"name": "garlic", "quantity": 6, "unit": "clove", "note": "smashed"}
],
"steps": [
"Heat the oven to 200 degrees Celsius.",
"Rub the chicken with zest, salt, and oil."
],
"tags": ["dinner", "roast", "gluten-free"]
}
Paste that into a validator before you trust it. The output should parse on the first attempt with no preprocessing. If it arrives with a code fence or a sentence in front, tighten rule one and lower the temperature to zero for the extraction call.
Why This Returns Valid JSON
Three design choices carry the result. First, showing the schema inline gives the model an exact target instead of a guess, which is the difference between a stable contract and a coin flip. Second, the raw-output rule removes the wrapper text that models add by default when they think they are talking to a person. Third, the null-and-error rules prevent the two silent killers of structured extraction: invented values and invented records. Together they turn a chat reply into data your parser can consume without a human in the loop.
Validation Traps
- Code fences. If your pipeline strips backticks, that is a bandage. Ban fences in the prompt so the raw output is clean at the source.
- Smart quotes. Curly quotes break strict parsers. Require straight double quotes explicitly.
- String numbers. A quantity of “two” versus 2 breaks math downstream. Require numeric types and null for unknowns.
- Silent invention. A model that fills a missing cook time with a plausible guess corrupts your data quietly. Demand null.
- No retry path. Always validate against a schema and send failures back once with the validator error, rather than trusting the first pass.
Schema Variations
- Batch input: change the top level to an array and add “Return a list of objects, one per recipe, in the same order as the input.”
- Nested steps with timing: add “Give each step an object with text, duration_minutes, and equipment.”
- Metric conversion: add “Normalize all quantities to grams and milliliters and keep the original in a raw field.”
- Strict enums: add “unit must be one of gram, milliliter, unit, clove, slice” so downstream code can switch on it safely.
- Confidence score: add “Include a confidence field from 0 to 1 for each ingredient when the text is ambiguous.”
Treat the prompt and the schema as one artifact and version them together, so a schema change never silently ships ahead of the prompt. To control how the format is framed versus what is asked, read System vs User Prompt. To lock the shape with a worked example, see One-Shot vs Few-Shot Prompting, and to make extraction deterministic, use the temperature and top-p guide.
Sources & Notes
Prompt pattern written for ChatGPT (GPT-4o and later) and portable to Claude and Gemini with minor wording changes; the same contract maps to JSON-mode or structured-output features where a provider supports them. Tested behavior: an explicit raw-output rule plus a lower temperature reduces code-fence wrappers and type drift compared with a plain request for JSON. No external data or package versions were fetched, and the example recipe object is illustrative. Always validate model output against a schema and treat the first response as a draft, not a guaranteed record.
