Copy & Paste Confluence Forge Macros like a Pro: Sharing Stateful Forge Macros via URL

I thought to share some community love by proposing a solution to this (my own) question :grin:

Shortly after we released Advanced Content Status & Labels (AKA as Awesome Pills) some early-adopting power-users, like our Marketing Hero @SeanManwarring , started asking for ‘copy and paste’ of the macro to speed up making all sorts of TODO, status, feature road maps and task lists.

Sounds good: roadmap now

Copy and paste macros: good luck (not)

Copy and paste of a stateful forge app macro doesn’t work in the Confluence editor, except of course for Atlassian maintained Forge macros. After pasting any stateful forge app macro you just get a stateless macro placeholder.

Forge macros often rely on internal state stored in content properties or storage APIs - like this one always needs a Key & Value pair and some metadata like colour and author etc.

Repurpose Forge Macro Autoconvert

Forge macro autoconvert originally serves the purpose of ‘importing’ links from the WWW into a Forge macro. This could be a link to a Github file, a Google doc or anything really that the macro can ‘digest’ and render.
Paste anything really? Like a URL that encodes the state of an existing Content Status Macro? Hmm, that could work!

paste pill

The Mechanism

The macro offers its internal copy button which copies a URL that encodes its state into the browser clipboard. The domain of this encoded URL can be anything, it just needs to match the pattern declared in the manifest, for example:

modules:
  macro:
    - key: pill
      autoConvert:
        matchers:
          - pattern: https://ilovealassi.net/pill/*

When the URL is pasted into the editor, Confluence Forge magically ‘picks’ your macro based on the URL pattern and renders it with context information containing context?.extension.autoConvertLink which your macro logic can happily decode and use, in order to render the macro in its intended state.

Some Caveats and security considerations

URL limits

Confluence (and browsers in general) impose practical limits on URL lengths. The safest range is typically:

  • < 2000 characters for full compatibility (Chrome has a 2048 character limit)
  • Prefer < 1000 characters for mobile-friendliness and clipboard reliability

This means your macro state must be:

  • Compact (e.g., store {"theme":"dark","items":[...]} as a minified JSON string)
  • Serialized efficiently (e.g., use JSON.stringify, then base64 or URI-encode)

Consider an alternative method like storing sensitive state securely using the Forge Storage API, keyed by a short ID in the URL and then retrieve the state from Forge KVS via the key (don’t forget to purge the object).

Security: Input Validation & Sanitization

Because the macro auto-convert feature triggers on a pasted URL, users or malicious actors could tamper with the URL and feed your macro arbitrary state values.

Mitigation steps:

  • Strict schema validation: Use a schema (e.g., Zod or custom validation) to validate decoded state objects.
  • Do not decode blindly: Avoid using eval, Function, or running untrusted strings.
    Stick to decoding only from formats you control (like base64 + JSON).

Prevent URL Tampering Attacks

If macro state encodes sensitive logic (e.g., access scopes or user privileges), users could manipulate the URL to elevate access.

Defenses:

  • Do not encode user identity, permissions, or tokens in the URL
  • Store sensitive state securely using the Forge Storage API, keyed by a short ID in the URL
  • Optionally sign the state blob (e.g., with an HMAC) and verify it on decode
2 Likes