TL;DR: XML tags mark the boundaries between the parts of a Claude prompt. Anthropic's docs say they help Claude parse complex prompts unambiguously when a prompt mixes instructions, context, examples and variable inputs. Use consistent, descriptive tag names, nest them when the content has a natural hierarchy, and never treat a tag as a security boundary.
What are XML tags in a Claude prompt?
XML tags in a Claude prompt are angle-bracket labels you put around each part of the prompt so the model can tell one part from another. <instructions> holds what you want done. <context> holds background. <input> holds the thing to operate on. They are delimiters, not markup that gets parsed and executed.
Here is the claim from Anthropic's own prompting reference, accessed August 26, 2026:
XML tags help Claude parse complex prompts unambiguously, especially when your prompt mixes instructions, context, examples, and variable inputs. Wrapping each type of content in its own tag (for example,
<instructions>,<context>,<input>) reduces misinterpretation.
Note the shape of that sentence. It is about parsing an ambiguous blob, not about a magic performance multiplier. If your prompt is one clear paragraph, tags buy you nothing. The gains show up when four different kinds of content are competing for the model's attention inside one wall of text.
The same page lists exactly two best practices: use consistent, descriptive tag names across your prompts, and nest tags when the content has a natural hierarchy.
The same prompt, without tags and with them
Here is a support triage prompt written the way most people write it first.
You are a support triage assistant for a SaaS product. Our refund window is 14 days
from purchase and we do not refund annual plans after 30 days. Categorise the ticket
below as billing, bug, or feature request, then draft a two-sentence reply. Ticket:
Hi, I bought the annual plan six weeks ago and the export button hasn't worked since
Tuesday. Can I get my money back? Also please add a dark mode. Keep the tone warm but
do not promise a refund.
Everything is true and everything is in there. The problem is that the ticket text and the policy text and the instruction text are all the same kind of text. The ticket itself contains a refund request, a bug report and a feature request, and it also contains something that reads like an instruction to you. The model has to guess which sentences are commands from you and which are quotes from a customer.
Now the same content, tagged.
<instructions>
Categorise the ticket as exactly one of: billing, bug, feature_request.
Then draft a reply of no more than two sentences.
Return your answer as: category on the first line, reply on the second.
</instructions>
<policy>
Refund window is 14 days from purchase.
Annual plans are not refundable after 30 days.
Never promise a refund in the reply.
Tone: warm, direct, no apologising twice.
</policy>
<ticket>
Hi, I bought the annual plan six weeks ago and the export button hasn't worked since
Tuesday. Can I get my money back? Also please add a dark mode.
</ticket>
Nothing was added. Three boundaries were. The model no longer has to infer that "keep the tone warm" is your instruction while "please add a dark mode" is the customer's. That inference is the failure mode tags remove.
Why do XML tags help Claude?
Because they make the boundaries explicit, and Anthropic says so directly. That is the whole mechanism as documented.
It is worth being blunt about what the docs do not say, because a lot of recycled advice does. The current Anthropic documentation makes no claim that Claude was specially trained or fine-tuned to recognise XML. That line circulated widely from older prompt-engineering write-ups. The page live today, at platform.claude.com, says tags help Claude parse complex prompts unambiguously. Quote that, not the folklore.
A second thing the docs do not say: that tags must be valid XML. Anthropic's own long-context example puts a <documents> block in a prompt and then follows it with a bare sentence of instruction. No root element, no declaration, nothing a real XML parser would accept. The angle brackets are doing the job of a heading, not the job of a schema.
Which tags should you use for instructions, context, input and examples?
Anthropic names <instructions>, <context> and <input> as examples rather than as a fixed vocabulary, then gives two conventions it actually specifies. Examples go inside <example> tags, with several of them grouped in an <examples> wrapper, so Claude can distinguish them from instructions. The docs recommend three to five examples for best results. Long documents go inside a <documents> wrapper.
Everything else is yours to name, and the naming matters more than the choice. Consistency across a prompt family is the documented best practice.
| Content type | Tag Anthropic uses or implies | Status in the docs |
|---|---|---|
| What to do | <instructions> | Named as an example |
| Background the model should know | <context> | Named as an example |
| The variable payload to operate on | <input> | Named as an example |
| One demonstration | <example> | Specified for few-shot prompting |
| A set of demonstrations | <examples> | Specified as the wrapper |
| A set of source documents | <documents> | Specified for long context |
| One source document | <document index="n"> | Specified, with an index attribute |
| Where a document came from | <source> | Specified as a child element |
| The document body | <document_content> | Specified as a child element |
| Extracted supporting quotes | <quotes> | Used in Anthropic's grounding example |
| Reasoning kept apart from the answer | <thinking> and <answer> | Used in the manual chain-of-thought fallback |
Anthropic also uses descriptive tags as scoped behavioural policies inside a system prompt, with names like <default_to_action>, <use_parallel_tool_calls> and <avoid_excessive_markdown_and_bullet_points>. That is a pattern worth stealing. A named block gives you something you can add, remove or A/B test as a unit, instead of a policy sentence buried in paragraph four.
How do you nest XML tags in a Claude prompt?
Nest when the content has a real hierarchy, which is Anthropic's stated rule. The canonical case is multiple documents, where each one carries its own metadata. Here is the structure from Anthropic's long-context guidance, reproduced from the docs page accessed August 26, 2026:
<documents>
<document index="1">
<source>annual_report_2023.pdf</source>
<document_content>
{{ANNUAL_REPORT}}
</document_content>
</document>
<document index="2">
<source>competitor_analysis_q2.xlsx</source>
<document_content>
{{COMPETITOR_ANALYSIS}}
</document_content>
</document>
</documents>
Analyze the annual report and competitor analysis. Identify strategic advantages and
recommend Q3 focus areas.
Three things in that snippet are doing work. The index attribute gives the model a handle it can cite. The <source> element tells it where the text came from, which changes how much authority the text should carry. And the instruction sits after the documents, not before them.
That last one is the part people get backwards. Anthropic's long-context guidance says to put long documents near the top of the prompt, above your query, instructions and examples, for inputs above roughly 20,000 tokens. The docs add that queries at the end can improve response quality by up to 30 percent in tests, especially with complex multi-document inputs. That is Anthropic's own figure, published on its prompting best practices page, and it is the reason the tagged block leads and the instruction trails.
There is a related trick on the same page: for long-document work, ask Claude to pull relevant quotes into a <quotes> block first, then answer from those. Tags give you a place to put the intermediate step so it does not contaminate the final answer.
How do XML tags interact with Claude's system parameter?
Tags and the system prompt are separate mechanisms that compose freely. Tags are text formatting. The system prompt is a place to put text.
On Anthropic's Messages API, the system prompt is a top-level system parameter. The API reference is explicit that there is no "system" role for input messages in the Messages API, which is the first thing to unlearn if you came from an API where system is a message role. If you are mapping roles across vendors, we covered which role actually wins on each provider in a separate post.
That parameter takes a string or an array of text blocks, and tagged text is just text. So the practical layout for a production Claude prompt looks like this:
{
"model": "claude-opus-5",
"max_tokens": 2048,
"system": "You are a support triage assistant for AcmeCloud.\n\n<policy>\nRefund window is 14 days from purchase.\nAnnual plans are not refundable after 30 days.\nNever promise a refund.\n</policy>\n\n<output_contract>\nLine 1: one of billing | bug | feature_request\nLine 2: a reply of at most two sentences\n</output_contract>",
"messages": [
{
"role": "user",
"content": "<ticket>\nI bought the annual plan six weeks ago and the export button stopped working on Tuesday. Can I get a refund? Also please add dark mode.\n</ticket>"
}
]
}
Stable things go in system: the role, the policy, the output contract. The variable payload goes in the user turn, in its own tag. That split is not cosmetic. It maps onto prompt caching, where the front of the request is the part that stays identical between calls and therefore the part that can be cached.
One recent wrinkle worth knowing. Since May 28, 2026, Anthropic has shipped mid-conversation system messages, which do let you send a {"role": "system"} message inside the messages array on certain models. Anthropic's own page describes them as a cache-preserving alternative to editing the top-level system field partway through a long session. The top-level parameter is still where a system prompt normally lives, and the feature is model-dependent, so check the compatibility note on that page before you build on it.
Are XML tags a security boundary?
No. This is the most important paragraph on the page.
A tag is a suggestion about how to read the surrounding text. Nothing enforces it. If untrusted content lands inside your <ticket> block and that content contains </ticket> followed by a fresh instruction, the boundary you thought you had is gone. Anthropic says as much in its own guidance on mitigating jailbreaks and prompt injection, where it recommends JSON-encoding third-party strings precisely so that "an attacker cannot close a quote or tag to break out into an instruction context."
That page, accessed August 26, 2026, sets out the defences that actually carry weight. Deliver third-party content inside tool_result blocks rather than in system prompts or plain user text, because Claude is trained to treat instructions inside tool results with skepticism. Tell the model in the tool description what the content is and where it came from. State an untrusted-content policy in your system prompt, in a named tag. JSON-encode the payload. Screen tool output with a small classifier before it reaches the main model. Apply least privilege so a successful injection reaches nothing valuable. Red-team your own agent before you ship it.
Notice that only one item on that list is a tag, and it is the one that states a policy, not the one that wraps the payload.
Can XML tags control Claude's output as well as its input?
Partly, and there is a better tool for the strict version.
Anthropic lists XML format indicators as one of the effective ways to steer output formatting: rather than describing the shape you want, ask for it by tag, as in "write the prose sections of your response in <smoothly_flowing_prose_paragraphs> tags." The docs pair this with a more general principle, which is to tell Claude what to do instead of what not to do, and to match your prompt's own formatting style to the output style you want.
Two caveats, both from the same source.
The first is that prefilling is gone. Starting with Claude 4.6 models, supplying a partial assistant message for Claude to continue from is no longer supported, and such requests return a 400. If you were using a prefill to force a <result> opening tag, the documented migrations are to instruct the model directly, to route the request through structured outputs, or to use tool calling.
The second is that for guaranteed schema conformance, tags are the wrong instrument. Anthropic's own consistency guidance points at structured outputs for that, and the structured outputs feature constrains the response to a JSON schema rather than hoping the model closes its tags. If your downstream code will JSON.parse the result, use the feature. If a human is reading the result and you want readable sections, use tags. We wrote up the general version of that decision in our piece on JSON prompts.
There is also a specific gotcha for reasoning tags. Anthropic's docs still endorse <thinking> and <answer> as a manual reasoning fallback when thinking is off, and endorse showing <thinking> inside few-shot examples. But they add a warning for Claude Opus 5: with thinking disabled, the model can occasionally emit internal XML tags into its visible output. If you are parsing on tag boundaries, that will bite you.
Is XML tagging a Claude-specific technique?
The conventions are Claude-specific. The idea is not, and it would be dishonest to pretend otherwise.
Anthropic documents tags as a first-class technique for Claude and specifies actual tag names for examples and documents. That vocabulary carries no special meaning anywhere else. OpenAI's prompt engineering guide, accessed August 26, 2026, says you can help the model understand logical boundaries "using a combination of Markdown formatting and XML tags", listing XML as one delimiter option next to Markdown rather than as the house style. Its GPT-4.1 guidance goes further and notes that the right delimiter depends on your content: if you are retrieving documents that contain a lot of XML, an XML-based delimiter will likely be less effective.
That last point applies to Claude too, and nobody says it enough. If your <input> block is full of HTML, your delimiters no longer stand out. Switch to a delimiter your content does not contain, or JSON-encode the payload.
So the accurate framing is: XML tags are a documented Claude technique with a documented Claude vocabulary, they are a supported option on at least one other major provider, and they are not a law of language models. If you are moving prompts between models, that difference is worth planning for, which is roughly the argument we made comparing ChatGPT and Claude prompt styles.
A copy-paste XML scaffold for Claude
This is the skeleton I use. Delete the blocks you do not need rather than adding blocks you might.
<role>
You are a [specific role] working for [specific organisation or product].
</role>
<instructions>
1. [First step, imperative, one action]
2. [Second step]
3. [Third step]
Do not [the single most likely wrong turn].
</instructions>
<context>
[Background the model cannot infer: audience, product facts, house policy,
what has already been tried.]
</context>
<examples>
<example>
<input>[a realistic input]</input>
<output>[the output you would accept without editing]</output>
</example>
<example>
<input>[an edge case, deliberately different from the first]</input>
<output>[the correct handling of it]</output>
</example>
</examples>
<input>
{{THE_THING_TO_OPERATE_ON}}
</input>
<output_contract>
Format: [exact shape]
Length: [hard limit]
If you are missing information you need, ask one clarifying question instead of guessing.
</output_contract>
Five checks before you ship a tagged prompt:
- Every tag opens and closes. Anthropic publishes no well-formedness rule, but the model is pattern-matching on your structure and a dangling tag is a worse pattern.
- Tag names are consistent across the family. If one prompt says
<input>and its sibling says<user_input>, you have two vocabularies to maintain and no reason for it. - Long content is at the top, the question is at the bottom. That is the documented ordering for large inputs.
- Untrusted content is not merely tagged. It is JSON-encoded, delivered in a tool result, or both.
- Nothing is nested more than two levels deep unless the content genuinely has three levels.
If you keep a library of these, the reusable part is the scaffold, not the prompt. That is the same argument for keeping prompts somewhere other than your chat history, which we made in the guide to syncing prompts across ChatGPT, Claude and Gemini.
Where Prompt Architects fits
Our enhancer takes a one-line prompt and returns a structured one: Role, Task, Format, Constraints and Tone. Those five sections are exactly the blocks you would wrap in tags for Claude, so the tagging becomes a short edit on top of a structure that already exists rather than a blank-page problem. Enhancement runs in under two seconds, there is a free plan, and the browser extension works natively on Claude alongside ChatGPT, Gemini, Grok and Perplexity.
If you work in Claude Desktop or Claude Code rather than a browser, our MCP server exposes the same improve, refine and shorten tools inside the client, so you can restructure a prompt without leaving the session.
Honest scope note: we generate and manage prompts. We are not an evaluation harness and we do not run experiments against your traffic. If what you need is statistical evidence that one tagged variant beats another on your data, you want an eval tool, and you should reach for one.
Stop rewriting prompts. Start shipping.
Works with ChatGPT, Claude, Gemini, Grok, Midjourney, Ideogram, Veo3 & Kling. 5.0★ on the Chrome Web Store.
Create An Account