How to resolve Referenced Images

#Supporting the Referenced Image macro in your app

Capable for Confluence and Capable Images for Confluence support the Referenced image macro, letting you include one image on multiple pages and update it once to reflect everywhere. This suits documentation and knowledge bases well.

This page explains how to read a Referenced image macro and pull the underlying image, the same way Capable Sites does it during a site export.

#Step 1: Get the macro config out of the ADF

The macro is a Forge extension node in the ADF of a Confluence page. Its config lives under attrs.parameters:

{
  "type": "extension",
  "attrs": {
    "extensionKey": "<appId>/<envId>/static/<appHash>-cf-mc-imgref",
    "parameters": {
      "guestParams": {
        "imageId": "cc-12345678",
        "imageTitle": "Product logo",
        "aspectRatio": "16:9",
        "alignment": "center",
        "showCaption": true
      }
    }
  }
}

Depending on the app, the extension key differs:

# Capable for Confluence
App ID   - 940ba09e-2961-4460-b5d2-92bc1d4754e8
Env ID   - a4748ec2-e494-4e79-8df6-4bef5e1e06a3
Macro ID - njyzjq-cf-mc-imgref

# Capable Images for Confluence
App ID   - d8793129-11a0-4c18-95d6-1a929675d702
Env ID   - 2d326cd8-28a0-408d-9d0e-c55ae8fffd4f
Macro ID - mmving-cf-mc-imgref

Find pages containing the macro with CQL:

macro = "njyzjq-cf-mc-imgref" OR macro = "mmving-cf-mc-imgref"

#Step 2: Fetch the Referenced Image asset

imageId is the id of a Confluence custom-content entity. Fetch it with body-format=raw; the raw body is a JSON string describing the asset.

GET /wiki/api/v2/custom-content/{imageId}?body-format=raw
Accept: application/json
const cc   = await res.json();
const body = JSON.parse(cc.body.raw.value); // the record described below

The parsed body is the stored asset record. The image payload is nested under data (a tagged union on data.type), and thumbnail fields sit at the top level:

{
  "title": "Product logo",          // caption fallback
  "data": {
    "type": "attachment",
    "attachment": {
      "id":        "att-998877",     // attachment id — child of the custom-content entity
      "title":     "product-logo.png",
      "extension": "png",
      "version":   3,
      "checksum":  "a1b2c3d4"        // changes when the image is replaced
    },
    "url": "..."                     // optional pre-computed URL (browser-session only — see note)
  },
  "thumbnailId":        "att-112233", // low-res fallback attachment
  "thumbnailExtension": "png"
}

#Step 3: Download the image

Download the full-resolution attachment by its id from the custom-content container, using the Confluence REST child-attachment endpoint:

GET /wiki/rest/api/content/{imageId}/child/attachment/{data.attachment.id}/download
  • {imageId} — the custom-content id (the container the attachment is a child of).

  • {data.attachment.id} — the att-xxx attachment id from Step 2.

Fetch it with app authentication (Forge principal: 'app').

Do not use /wiki/download/attachments/{imageId}/{filename} for server-side fetches. That public download URL (and the v2 _links.download link) returns 401 "scope does not match" for app-scoped Forge fetch. The /child/attachment/{id}/download REST path is the one that works for app auth. The data.url field and the /wiki/download/... form only resolve inside an authenticated end-user browser session (e.g. an <img> tag), not from your backend.

#Thumbnail fallback

If data.attachment.id is missing, or the full-res download fails, fall back to the thumbnail — same container, thumbnailId as the attachment, thumbnailExtension for the file extension:

GET /wiki/rest/api/content/{imageId}/child/attachment/{thumbnailId}/download

#If you only have the attachment id (no container)

Resolve the container first, then download:

GET /wiki/api/v2/attachments/{attachmentId}