How to get a list of Confluence Apps and their licensing information

Platform Notice: Data Center Only - This article only applies to Atlassian products on the Data Center platform.

Note that this KB was created for the Data Center version of the product. Data Center KBs for non-Data-Center-specific features may also work for Server versions of the product, however they have not been tested. Support for Server* products ended on February 15th 2024. If you are running a Server product, you can visit the Atlassian Server end of support announcement to review your migration options.

*Except Fisheye and Crucible

Summary

Apps (also known as Add-ons and Plugins) are a good way to extend Confluence functionality and they are available to administrators from the Atlassian Marketplace.

Confluence administrators may need to generate reports about licensing status of the Apps installed on their instances. For example, if you need to get the license expiry date of every installed App, this can be done from the web UI checking each App at a time. For large Confluence instances this can be time consuming.

Atlassian Universal Plugin Manager (UPM) exposes REST API methods that helps to manage the installed Apps, including their licensing information.

This document will guide you on how to create a script that uses these REST API methods to create a CSV-like report on installed Apps and their licensing information.

Solution

The solution is based on UPM's REST API methods by running a script on any computer/server with access to Confluence. It could be the Confluence server itself or your own computer.

The main steps of the code are:

  1. Get a list of all Apps using /rest/plugins/latest method.

  2. For each App, get their license information.

Below you will find the suggested script on which the output is a CSV-like report with the semi-colon ':' as the separator.

Specifics for each language:

  • Shell Script.

    • You must install jq CLI.

    • A temporary file will be saved as /tmp/restapi.out.

    • The full report is stored in file /tmp/PluginReport.csv.

  • Node.js.

  • PowerShell

    • Script was created and tested on PSVersion 6.0.2.

Shell script source code

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ### Final report is saved on file /tmp/PluginReport.csv ### Change these arguments according to your instance CONFLUENCE_SERVER_URL="http://localhost:6663" CONFLUENCE_SERVER_CONTEXT_PATH="/c663" ADMIN_USRNAME=admin ADMIN_PWD=admin CONFLUENCE_BASE_URL=$CONFLUENCE_SERVER_URL$CONFLUENCE_SERVER_CONTEXT_PATH curl --user $ADMIN_USRNAME:$ADMIN_PWD $CONFLUENCE_BASE_URL/rest/plugins/latest/ 2>/dev/null | jq -r '.plugins[] | select(.userInstalled) | "\(.name):\(.version):\(.vendor.name):\(.usesLicensing):\(.links.self)"' > /tmp/restapi.out echo "Plugin Name:Plugin Version:Vendor Name:Use License:License Type:Expiry Date:License Key:SEN" > /tmp/PluginReport.csv while read PLUGINLINE; do PLUGINKEY=$(awk 'BEGIN { FS=":" } { print $5 }' <<< "$PLUGINLINE") LICINFO=$(curl --user $ADMIN_USRNAME:$ADMIN_PWD $CONFLUENCE_SERVER_URL$PLUGINKEY/license/ 2>/dev/null | jq '"\(.licenseType):\(.maintenanceExpiryDateString):\(.rawLicense):\(.supportEntitlementNumber)"' | sed -e 's/^"//' -e 's/"$//') PLGINFO=$(awk 'BEGIN { FS=":"; OFS=":"; } { print $1,$2,$3,$4 }' <<< "$PLUGINLINE") echo "$PLGINFO:$LICINFO" done < /tmp/restapi.out >> /tmp/PluginReport.csv

Node.js source code

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 /* --- Change the values of these parameters --- */ var confluenceServerUrl = 'http://localhost:6663'; // Confluence URL var confluenceContextPath = '/c663'; // context path //var confluenceContextPath = '/c663'; // context path var credentials = { 'username' : 'admin', 'password' : 'admin' }; // these are the admin credentials /* --------------------------------------------- */ var confluenceBaseUrl = confluenceServerUrl + confluenceContextPath; const axios = require('axios'); const axios2 = require('axios'); const getConfluenceApps = async () => { try { return await axios.get(confluenceBaseUrl + '/rest/plugins/latest/', { auth: credentials }) } catch (error) { console.log(error) } } const getAppAdditionalInfo = async urlToApp => { try { return await axios2.get(confluenceServerUrl + urlToApp + '/license/', { auth: credentials }) } catch (error) { console.log(error) } } const filterInstalledApps = async () => { const confluenceApps = await getConfluenceApps(); // filter for user installed Apps let installedApps = confluenceApps.data; installedApps.plugins = installedApps.plugins.filter(function(eachApp){ return eachApp.userInstalled != false; }); // print header console.log('"Plugin Name":"Plugin Version":"Vendor Name":"Use License":"License Type":"Expiry Date":"License Key":"SEN"'); // for each app for (itemId in installedApps.plugins) { let appDetailedInfo = (await getAppAdditionalInfo(installedApps.plugins[itemId].links.self)).data; console.log('"' + installedApps.plugins[itemId].name + '":"' + installedApps.plugins[itemId].version + '":"' + installedApps.plugins[itemId].vendor.name + '":"' + installedApps.plugins[itemId].usesLicensing + '":"' + appDetailedInfo.licenseType + '":"' + appDetailedInfo.maintenanceExpiryDateString + '":"' + appDetailedInfo.rawLicense + '":"' + appDetailedInfo.supportEntitlementNumber + '"'); } } filterInstalledApps();

PowerShell source code

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 ### --- Change the values of these parameters --- ### $username = "local_admin" $password = "local_admin" $confluence_server_url = "http://localhost:2667"; $confluence_server_context_path = "/c667"; ### --------------------------------------------- ### $confluence_base_url = $confluence_server_url + $confluence_server_context_path; ### Confluence Base URL ### Basic Authentication function Get-BasicAuthCreds { param([string]$Username,[string]$Password) $AuthString = "{0}:{1}" -f $Username,$Password $AuthBytes = [System.Text.Encoding]::Ascii.GetBytes($AuthString) return [Convert]::ToBase64String($AuthBytes) } $BasicCreds = Get-BasicAuthCreds -Username $username -Password $password; ### Collect All plugins info from rest API $plugins_rest_url = $confluence_base_url + '/rest/plugins/latest/'; $plugins_rest_output = Invoke-RestMethod -Uri $plugins_rest_url -Method Get -ContentType 'application/json' -Headers @{"Authorization"="Basic $BasicCreds"}; ### Filter for user installed Apps and select wanted attributes $filtered_plugins = $plugins_rest_output.plugins | where userInstalled -eq "True" | select -prop name,version,@{Name="VendorName"; Expression = {$_.vendor.name}},usesLicensing,@{Name="link"; Expression = {$_.links.self}}; $filtered_plugins | ForEach-Object -Process {$_.link = $confluence_server_url + $_.link + '/license/'}; ### Run license check rest api for each App $filtered_plugins | ForEach-Object -Process {$_.link = Invoke-RestMethod -Uri $_.link -Method Get -ContentType 'application/json' -Headers @{"Authorization"="Basic $BasicCreds"}}; ### Show selected attributes and convert output to CSV $filtered_plugins | select -prop name,version,VendorName,usesLicensing,@{Name="LicenseType"; Expression = {$_.link.licenseType}},@{Name="ExpiryDateString"; Expression = {$_.link.expiryDateString}},@{Name="LicenseKey"; Expression = {$_.link.rawLicense}},@{Name="SEN"; Expression = {$_.link.supportEntitlementNumber}} | ConvertTo-Csv -Delimiter ':'

If you face below errors while executing the script, please increase the rate limit while using this script

1 Invoke-RestMethod : The remote server returned an error: (429) Too Many Requests.

Below is an example of a report after pasting it in a spreadsheet application.

(Auto-migrated image: description temporarily unavailable)

Updated on April 8, 2025

Still need help?

The Atlassian Community is here for you.