Stand with Ukraine 🇺🇦
Products
Services
Blog
About Us

JavaScript in Macro

When working with User Macros in Confluence Cloud, the use of JavaScript depends on the macro type and its rendering constraints:

Static Macros

JavaScript is not allowed in macros of the "Static" type. This restriction arises from the Confluence Storage Format (official documentation), which enforces strict compliance with its rules. Any unsupported code, including JavaScript, is automatically removed before being sent to the client.

Dynamic Macros

JavaScript is allowed in "Dynamic" macros, enabling interactive functionality. However, to ensure security:

  • JavaScript runs in a sandboxed environment within an iFrame.

  • The iFrame enforces limited functionality, restricting access to certain APIs and ensuring the Confluence instance remains secure.

{"timestamp":1792799573528,"msg":"A unknown Exception Occurred","errorMsg":"The provided AtlassianHostUser did not specify a user to act as.","code":"500"}

Combine server-side render with client js

UM use Velocity as the templating engine for rendering. All requests and data processing are handled on the server-side, except for JavaScript execution. To use JavaScript on the client-side, wrap the logic inside a <script> tag. You can access Velocity-defined variables within the script using standard JavaScript.

image-20250205-161517.png
## Show flag if current page has unresolved inline comments:

#set($inlineComments = $ConfluenceManager.get("/wiki/api/v2/pages/${page.id}/inline-comments"))
#set($count = 0)

#foreach($comment in $inlineComments.results)
 #if($comment.resolutionStatus != "resolved")
    #set( $count = $count + 1 )
  #end
#end

<script>
  $count && 
    AP.flag.create({
      type: "info",
      title: "Info",
      body: "This page has " + $count + " unresolved comment" + ($count > 1 ? "s." : "."),
    });
</script>

Request Handling

{"timestamp":1792799573578,"msg":"A unknown Exception Occurred","errorMsg":"The provided AtlassianHostUser did not specify a user to act as.","code":"500"}

For client-side requests, use fetch() or XMLHttpRequest. To made authenticated requests to Confluence APIs, use AP.request().

Accessing Intranet Resources

Scripts running on the client side can send requests via a VPN (through the user's browser), enabling access to intranet resources that are otherwise restricted.

Javascript enrichment

Template of dynamic macros are nested in additional iframe. This additional (inner) iframe sandboxed with sandbox restriction for security reason and enable only inner javascript with sandbox="allow-scripts". To overcome this limitation of iframes Atlassian Connect JavaScript API (AP) and Atlassian User Interface components could be used.

Atlassian Connect JavaScript features (AP)

Read more about Connect JavaScript API.

 Context

Retrieves the current user context.

AP.context.getContext(function(response){
  console.log(response);
});

## Output
{
  "confluence": {
    "editor": {
      "version": "<string>"
    },
    "macro": {
      "outputType": "<string>",
      "hash": "<string>",
      "id": "<string>"
    },
    "content": {
      "type": "<string>",
      "version": "<string>",
      "id": "<string>"
    },
    "space": {
      "key": "<string>",
      "id": "<string>"
    }
  },
  "url": {
    "displayUrl": "https://*.atlassian.net/wiki"
  }
}
 Cookie

Store data in the Atlassian product's localStorage.

AP.cookie.save('my_cookie', 'my value', 1);
 Flag

Provide system feedback in the product user interface.

const flag = AP.flag.create({
  title: 'Successfully created a flag.',
  body: 'This is a flag.',
  type: 'success',
});
 Iframe

Resize the iframe to actual iframe size automatically on size change.

AP.resize('400','400');
 Navigator

Navigates the user from the current page to the specified page.

AP.navigator.go('contentview', {contentId: '12345', versionOverride: 2});

Triggers a reload of the parent page.

AP.navigator.reload();
 Request

Provides an XMLHttpRequest to the host product without requiring CORS.

AP.request('/rest/api/user/current')
  .then(data => console.log(data))
  .catch(error => console.log(error));

Unavailable Features

{"timestamp":1792799573581,"msg":"A unknown Exception Occurred","errorMsg":"The provided AtlassianHostUser did not specify a user to act as.","code":"500"}
 Confluence

Content context unavailable.

 Context getToken()

Current user context as a JWT token unavailable for security reason.

AP.context.getToken(function(token){
  console.log("JWT token string", token);
});
 Cookie read(), erase()
AP.cookie.read('my_cookie', function(value) { alert(value); });
AP.cookie.erase('my_cookie');
 Custom content

Provides functions to interact with the custom content. Has limited functionality because of event callback limitations.

 Dialog

Manage modal dialogs modules.

 Events

Callbacks not supported.

 History

Enabled for Page modules only.

 Iframe

Callbacks not supported.

AP.getLocation(function(location){
  alert(location);
});

Enabled for General Page modules only.

AP.sizeToParent();
 Inline dialog

Manage Inline dialogs shown via a web item target.

 Macro

Manage Macro module.

 Navigator

Callbacks not supported.

AP.navigator.getLocation(function (location) {
  console.log(location);
});
 Page

Enabled for General Page modules only.

 Scroll position

Callbacks not supported.

 Theming

Not supported.

 User

Callbacks not supported.

Atlassian User Interface (AUI)

AUI is connected via CDN to the rendered template by default, allowing styling through inline CSS classes and interaction using AJS.

Read more about Atlassian User Interface.

Usage example with AUI styles, AJS and AP feature:

load.gif
 ## Render button with loading state during resolving request:
 
 <button class="aui-button aui-button-primary" id="loadingButton">Make request</button>

 <script>
  AJS.$(document).on('click', '#loadingButton', function() {
    var that = this;
    if (!that.isBusy()) {
      that.busy();
      
      AP.request('/rest/api/user/current')
        .then((response) => {
          console.log({response})
          that.idle();
        })
    }
  });
 </script>