Stand with Ukraine 🇺🇦
Products
Services
Blog
About Us

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

Macros Rendered on Pages:

Screenshot 2025-01-28 at 23.24.47.png

Screenshot 2025-01-28 at 23.30.13-Photoroom.png