User Macro on-premise and Cloud
User Macros in Confluence Server/Data Center:
User macros in Confluence Server and Data Center are natively supported. They allow admins to create reusable custom macros using Velocity, HTML, Javascript, and/or Confluence Storage Format without the need for extensive development or external plugins.
User Macros in Confluence Cloud:
Confluence Cloud does not natively support traditional user macros. Instead, you can use apps like User Macro for Confluence Cloud that provide support for creating and managing user macros.
Key Differences:
Feature | Server/Data Center User Macros | Confluence Cloud User Macros |
|---|---|---|
Supportability | Natively supported | No native support; using a third-party app from the marketplace |
Ease of Use | Convenient: Created via the Confluence administration panel | Relatively convenient: Created via an external app |
Hosting | Runs directly on the Confluence instance | Hosted externally on the Marketplace Partners' servers |
Communication Interface | Direct access to the Confluence Java API | Access only via Confluence/Jira REST API |
Security Limitations | Any HTML, CSS, and JS content directly included into the page | Strict storage format or sandboxed iframe |
Differences in Practice:
In both Confluence Server/Data Center and Confluence Cloud, user macros are quite similar as they both use Velocity templates for rendering. However, there are key differences between them due to the underlying architecture.
Server/Data Center User Macros:
Rely on Confluence’s context to fetch attachment details, using — e.g.
$content— to retrieve data directly from the page context.
Cloud User Macros:
Interact with Confluence’s REST API to retrieve relevant data from cloud endpoints.
🔎 Take a look at the following examples and their outputs:
## SERVER SYNTAX
## @param ID:title=Page ID|type=int|desc=Page ID to fetch attachments from|default=-1
## Determine the target page ID
#set ($pageID = $paramID)
#if ($pageID == -1)
#set ($pageID = $content.id) ## Default to current page if no ID is provided
#end
## Placeholder for the attachment list (will be populated by JavaScript)
<div id="attachment-list-$pageID">
<aui-spinner size="large"></aui-spinner>
</div>
<script>
(function() {
var pageID = "$pageID";
var container = document.getElementById("attachment-list-" + pageID);
var baseUrl = window.location.origin;
fetch(baseUrl + "/rest/api/content/" + pageID + "/child/attachment")
.then(response => response.json())
.then(data => {
if (data.results && data.results.length > 0) {
var listHtml = "<ul>";
data.results.forEach(attachment => {
var fileName = attachment.title;
var fileUrl = baseUrl + attachment._links.download;
listHtml += `<li><a href="${fileUrl}" target="_blank">${fileName}</a></li>`;
});
listHtml += "</ul>";
container.innerHTML = listHtml;
} else {
container.innerHTML = "<p><strong>No attachments found</strong> for the specified page.</p>";
}
})
.catch(error => {
console.error("Error fetching attachments:", error);
container.innerHTML = "<p style='color:red;'><strong>Error fetching attachments.</strong></p>";
});
})();
</script>
## CLOUD SYNTAX
## Check if pageID is provided in user parameters
#set ($pageID = $parameters.pageID)
#if (!$pageID)
## If no pageID is provided, use current page's ID
#set ($pageID = $page.id)
#end
## Make a request to get attachment data
#set ($attachmentsResponse = $ConfluenceManager.get("/wiki/api/v2/pages/$pageID/attachments"))
## Render a list with clickable attachment items
#if ($attachmentsResponse.results && $attachmentsResponse.results.size() > 0)
<ul>
#foreach ($attachment in $attachmentsResponse.results)
<li>
<a href="${baseUrl}/${attachment.webuiLink}" target="_blank">
$attachment.title
</a>
</li>
#end
</ul>
#else
<p>
<strong>No attachments found</strong> for $page.title page or the page does not exist.
</p>
#end