Structured JSON Output

When your app needs to parse the reply, ask Claude for JSON in a defined shape.

When Claude's output feeds back into your code, you need it in a predictable structure — usually JSON. Claude is good at producing valid JSON when you describe the exact shape.

How to get reliable JSON

  • Describe every field and its type.
  • Give a small example of the exact structure.
  • Ask for JSON and nothing else — no prose around it.

Parse defensively

Even with clear instructions, wrap parsing in a try/catch. If Claude ever adds stray text, you can detect it and retry rather than crash.

Example

Example · javascript
const res = await client.messages.create({
  model: "claude-opus-4-8", max_tokens: 300,
  messages: [{
    role: "user",
    content:
      'Extract contact info as JSON with keys "name", "email", "company". ' +
      'Return only JSON.\n\n' +
      'Text: Jane Doe from Acme wrote in from [email protected] about pricing.',
  }],
});

const raw = res.content.find((b) => b.type === "text")?.text ?? "{}";
try {
  const data = JSON.parse(raw);
  console.log(data.email); // [email protected]
} catch {
  console.error("Model did not return valid JSON — retry or repair.");
}

When to use it

  • Parse product details from unstructured supplier emails into a typed object your database insert can consume directly.
  • Extract action items and assignees from a meeting transcript into a JSON array for your task-management app.
  • Classify user-submitted feedback into category, sentiment, and priority fields for a structured support queue.

More examples

Ask for JSON with a defined schema

Uses a system rule to ban prose and a schema hint in the user message to constrain the JSON shape.

Example · javascript
const msg = await client.messages.create({
  model: "claude-haiku-4-5",
  max_tokens: 128,
  system: "Respond only with valid JSON. No explanation, no code blocks.",
  messages: [{
    role: "user",
    content: `Extract from: "Jane Smith, [email protected], Senior Engineer".
Schema: {"name":string,"email":string,"role":string}`
  }],
});
const data = JSON.parse(msg.content[0].text);

Use a tool definition for reliable JSON

Forces tool_choice to a specific tool so the output is always a validated JS object, bypassing JSON.parse.

Example · javascript
const msg = await client.messages.create({
  model: "claude-haiku-4-5",
  max_tokens: 256,
  tools: [{
    name: "extract_contact",
    description: "Extract contact info from text.",
    input_schema: {
      type: "object",
      properties: {
        name:  { type: "string" },
        email: { type: "string", format: "email" },
        role:  { type: "string" }
      },
      required: ["name", "email"]
    }
  }],
  tool_choice: { type: "tool", name: "extract_contact" },
  messages: [{ role: "user", content: "Jane Smith, [email protected], Senior Engineer" }],
});
const data = msg.content[0].input; // already an object — no JSON.parse needed

Wrap parse in try/catch for safety

Strips code-fence wrappers Claude sometimes adds and throws a descriptive error if parsing still fails.

Example · javascript
function parseClaudeJson(text) {
  // Strip accidental code fences
  const clean = text.replace(/^```json\n?/, "").replace(/\n?```$/, "").trim();
  try {
    return JSON.parse(clean);
  } catch {
    throw new Error(`Claude returned invalid JSON: ${clean.slice(0, 80)}`);
  }
}

Discussion

  • Be the first to comment on this lesson.