Choosing Between Storage Format and Wiki Markup for Automated Confluence Page Creation
Guide to choosing between Confluence Storage Format (XHTML) and legacy Wiki Markup for automated page creation, with a comparison table, trade‑offs, and a concrete storage‑format implementation.
27 Nov 2025, 20:28 UTC

Decision and constraints
When building a pipeline that creates or updates Confluence pages programmatically, you must decide which content representation to send to the REST API. The choice affects portability across Cloud and Server/Data Center, macro handling, and the complexity of your template generator. Constraints typically include:
- Target deployment(s): Confluence Cloud, Server, or Data Center (or a mix).
- Required macros (e.g., info, note, task) and their correct rendering.
- Available authentication method (personal access token, basic auth, OAuth).
- Pipeline language and libraries (must be able to produce valid XHTML or wiki markup).
Comparison of supported options
| Aspect | Storage Format (XHTML) | Legacy Wiki Markup |
|---|---|---|
| Cloud support | Fully supported via v2 content API; recommended path. | Deprecated conversion endpoints; may be removed in future releases. |
| Server/Data Center support | Supported; same endpoints accept storage representation. | Still accepted via content endpoints, but behavior can diverge by version. |
| Macro representation | Expressed as ac:structured-macro elements with ac:parameter children. |
Macros written directly in wiki syntax (e.g., {info:title=Note}). |
| Verbosity | More verbose; requires proper XHTML escaping. | Concise and human‑readable. |
| Validation risk | Invalid XHTML (unclosed tags, raw &) leads to 400 errors or escaped output. | Malformed wiki markup may be silently ignored or render as plain text. |
| Pipeline complexity | Generator must emit valid XHTML and handle macro XML. | Generator can use simple string templates; however, you must maintain separate code paths for Cloud vs. Server if you rely on wiki markup. |
Trade‑off explanation
Storage Format shifts the burden of correctness to the client side: your template engine must produce well‑formed XHTML and correctly nest macro elements. This eliminates a server‑side conversion step and gives you identical behavior on Cloud and Server/Data Center, provided you target the same API version. The downside is increased template verbosity and the need to escape characters such as & and <.
Wiki Markup keeps templates short and easier to read, which can speed up initial development. However, the representation is not uniform: Cloud has deprecated the wiki‑to‑storage conversion endpoints, and Server/Data Center may accept wiki markup but render certain macros differently depending on the version. Maintaining a single pipeline that works everywhere therefore requires either branching logic based on deployment type or accepting the risk of future breakage.
Concrete implementation – using Storage Format
The following steps show how to create a page in Confluence Cloud (the same request works on Server/Data Center if you use the storage representation). Replace placeholders with your actual values.
- Prepare the XHTML payload. Ensure it is valid XHTML, escape special characters, and represent any macros with the
ac:structured-macropattern. Example for a simple page with an info panel:
<ac:structured-macro ac:name="info">
<ac:parameter ac:name="title">Important note</ac:parameter>
<ac:rich-text-body>
This is the content of the info panel.
</ac:rich-text-body>
</ac:structured-macro>
<p>Regular paragraph after the panel.</p>
- Set up the HTTP request. Use a tool that can send authenticated REST calls (e.g.,
curl, HTTP client library). Required permissions: the user or service account must have theCreatepermission in the target space.
curl -u <email>:<api_token> \ -X POST \ -H "Content-Type: application/json" \ -H "Accept: application/json" \ -d '{ "type": "page", "title": "Automated Test Page", "space": {"key": "TEST"}, "body": { "storage": { "value": "<ac:structured-macro ac:name=\"info\">\n <ac:parameter ac:name=\"title\">Important note</ac:parameter>\n <ac:rich-text-body>\n This is the content of the info panel.\n </ac:rich-text-body>\n</ac:structured-macro>\n<p>Regular paragraph after the panel.</p>", "representation": "storage" } } }' \ "https://your-instance.atlassian.net/wiki/rest/api/content"
- Check the response. A successful creation returns HTTP 200 with a JSON body containing the new page’s
idandversion. Record theidfor the next step.
- Validate the stored content. GET the page using the same authentication and ask for the storage representation:
curl -u <email>:<api_token> \ -H "Accept: application/json" \ "https://your-instance.atlassian.net/wiki/rest/api/content/<page_id>?expand=body.storage"Inspect the returned
body.storage.value. It should match the XHTML you sent (whitespace differences are acceptable). If the value is escaped or appears as plain text, the XHTML was invalid and Confluence fell back to escaping.
- Validate the rendered view. Retrieve the view URL (e.g.,
https://your-instance.atlassian.net/wiki/spaces/TEST/pages/<page_id>) in a browser or via a HEAD request and confirm that the info panel appears as a formatted panel, not as raw XML tags.Limitations and practical checks
- XHTML validity: Use an XML validator or a library that can serialize DOM to XHTML to avoid silent escaping. Invalid markup often produces a 400 response with a message like "Invalid content".
- Macro parameters: Some macros require specific parameter names; consult the macro documentation for your Confluence version to ensure you supply the correct
ac:parameterelements. - Attachments and images: If your XHTML references an attachment that has not yet been uploaded, the reference will render as a broken link. Upload the attachment first (via the
/child/attachmentendpoint) and use the returnedtinyIdin theri:attachmentelement. - Authentication risks: Personal access tokens (PATs) inherit the user’s permissions. If the token lacks space creation rights, the POST will return 403. Test with a least‑privileged service account that has only the needed permissions.
- Version pinning: The REST API version used in the URL (
/rest/api/content) is stable, but future Cloud releases may deprecate specific fields. Pin your pipeline to the API version documented in your Confluence release notes and monitor the changelog.
When to consider Wiki Markup
If you maintain a single codebase that targets only Server/Data Center instances and you have verified that the wiki‑markup endpoint is still accepted on your exact version, you may choose wiki markup for its brevity. In that case, repeat the validation steps above using body.representation: "wiki" and the raw wiki string in body.wiki.value. Keep in mind that any future Cloud migration will require a switch to storage format.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.