Collaborative editing for Confluence Server
Collaborative editing allows multiple people to concurrently edit a single Confluence page or blog post (we'll just call them pages from here on). When using collaborative editing, a page editor will see the avatar(s) of others editing the page, and the changes they make will appear in the editor in real time.
This page provides an overview of the various components that make up collaborative editing in Confluence Server. We'll go through how each component works, and how you can build plugins to integrate with them.
If you're developing for Confluence Cloud head to Collaborative editing for Confluence Cloud.
The shared draft vs personal draft model
We're changing the way drafts behave, and moving to a model that's more consistent with how content should be stored for collaborative editing. We'll call the outgoing model, used prior to collaborative editing, 'personal drafts', and the new model 'shared drafts'. The notable differences are:
- When editing a page prior to collaborative editing a new personal draft was created for each user, and the changes couldn't be seen by other users as personal drafts are private. Using collaborative editing a single shared draft is created for each page, and anyone editing the page will see the same draft.
- Personal drafts were represented by a
Draftclass, which extends
ContentEntityObjectand contains a
draftTypefield indicating whether the draft was a "
blogpost". We're deprecating the
Draftclass in favour of using the existing
Blogpostclasses, where a
contentStatusfield of "
draft"will indicate the object is a draft.
Comparing the personal draft and shared draft models:
|Personal drafts (before collaborative editing)||Shared drafts (collaborative editing)|
A draft page object in its different representations:
|Personal draft||Shared draft|
Shared drafts API
We provide a REST API that allows external interaction with shared drafts. The currently-supported operations are:
- Creating a shared draft
- Fetching a single or a list of shared drafts
- Publishing a draft
The Drafts API extends Confluence's existing REST API. In order to reference the draft, you'll need to add the following query parameter to REST requests:
For example, if the request to fetch an existing page is:
The request to fetch the corresponding draft will be:
Similarly, publishing a draft will be:
where the request payload will contain:
indicating that the status should be updated from "
draft" to "
When publishing drafts, it's also possible to specify a "
conflictPolicy" query parameter. Currently only the "
abort" policy is supported. This means that the publish operation will be aborted (and an error code returned) if a conflict is encountered during the publishing of a draft.
Draft operations are also exposed as a Java interface via the
ContentDraftService. These services are made available to plugins as Spring Beans with
You can create a shared draft by calling:
Note that the API currently only supports creating new shared drafts – it doesn't support creating a shared draft for an existing page.
To fetch a shared draft:
Finally, to publish a draft:
||Java||Triggered when a new shared draft gets created.||Event Listener Module|
||Java||Triggered when a shared draft is updated. This normally happens at regular intervals in an editing session when a draft is auto-saved.||Event Listener Module|
Extending the XWork actions
Shared draft support is provided to actions that extend the
Prior to shared drafts, actions could access drafts by calling
getDraft(). This method – to be deprecated – only returns the old
Draft class, which is incompatible with shared drafts. In order to support shared drafts you need to replace calls to
getDraftAsCEO, which will return a shared draft on instances that support them or a personal draft on other instances. This allows actions to maintain compatibility with instances that haven't been upgraded to collaborative editing.
You should ensure that future calls are made to
getContentDraft, which will only return shared drafts and doesn't provide support for personal drafts.
What happens to personal drafts once shared drafts have been rolled out?
Personal drafts will still be accessible from users' drafts list. They won't, however, be able to resume editing the draft in the editor. Opening a personal draft will display it in a read-only dialog, from which the user can copy the content into a new page.
How do shared drafts behave in the drafts list?
A user's drafts list will be populated with the following drafts:
- Personal drafts, created by the user
- Shared drafts created by the user but never published
Drafts that have a corresponding published page won't appear in the drafts list – users can access those drafts by editing the corresponding page.
Restoring historical versions
When a page is reverted, the corresponding shared draft is also updated to contain the new page content. This will also trigger an 'external changes' request (see our explanation of external changes).
Shared drafts will now implement the hierarchical interface (inherited from the
Blogpost classes), which means it's now possible to persist location onto drafts.
Drafts created using the
- Have its parent automatically set as the page from which user clicks the Create button
- Default to a space's home page if the parent page isn't specific (for example, when clicking Create from the dashboard)
We've also updated the move page dialog so that it persists the draft's location by calling
MovePageAction rather than temporarily storing the location on the client. This means the draft location will persist between different editing sessions.
Permissions and labels on shared drafts
There are two scenarios for draft metadata:
|A shared draft has never been published||
|A shared draft has been published and as such links with a corresponding page||
Sharing a shared draft
To collaborate on a shared draft that's linked to a published page, users only need to edit the published page.
To access a shared draft that's never been published, you need two pieces of information:
contentId(this will also be the
draftIdfor unpublished drafts)
draftShareIdof the draft
At the time a draft is created, a
draftShareId is generated and stored against the draft's content properties. This content and
draftShareId are displayed in the URL while the draft is being edited. It'll look like this:
Sharing this link with other users will allow them to edit the same draft, assuming the view and edit restrictions on the draft allow it.
Once a user accesses a draft with the correct
draftShareId they'll be granted a
ContentPermission#SHARED_PERMISSION, which allows them to make future edits to the draft without providing the
draftShareId. This shared permission won't be visible in the UI, and it'll be removed once the draft is published.
Stricter rules now apply to draft versioning. Whereas it was possible to save drafts as new versions prior to collaborative editing, this action is no longer permitted. Drafts must have a version of 1. If a version bump of a draft is attempted, Confluence will throw an exception.
Shared drafts, like personal drafts, aren't indexed in Confluence. Since they're not added to the content index, it means drafts won't appear in features that access the context index, including:
- Recently updated
- Space activity
Page updates triggered by draft publishes will appear in the content index as usual.
Collaborative editing modes in Confluence Server
In Confluence Server we provide administrators with a choice of three collaborative editing modes:
- On - use this mode to bring collaborative editing goodness and shared drafts to your teams. Collaborative editing is on by default when you install or upgrade Confluence.
- Limited - use this mode if you need to troubleshoot Synchrony problems. As the name suggests, editing functionality is limited, but users' shared drafts are protected. When a site is in limited mode, only one person can edit a shared draft at one time, people can't revert to an earlier version of the page in the page history, can't move pages and can't make inline comments on pages.
- Off - use this mode if you decide that collaborative editing is not right for your site (for example, there are strict auditing requirements that the collaborative editing experience can't meet yet). In this mode, people can only edit their own personal draft of a page. Confluence will attempt to merge any conflicts on save (similar to the Confluence 5 editing experience). Any existing Synchrony data contained in shared drafts is lost when the mode is changed to off.
Changing the mode is always initiated by the administrator. We do not automatically fall back to a particular mode at any time. You may want to test your add-on in all three modes.
Things to test
- The correct type of draft is created in the database – all drafts created after the the introduction of collaborative editing should be shared drafts.
- The correct type of draft is retrieved.
Synchrony is a service that allows the synchronisation of arbitrary data models in real time. It supports special synchronisation for HTML WYSIWYG editors, including telepointers (remote selections).
How does Synchrony work?
- Confluence is configured to communicate with the Synchrony service using an
- A JSON Web Token (JWT) is provided to clients containing the connection details
- A WebSocket session is opened to Synchrony using the provided JWT and the
contentIdof the page being edited
- The WebSocket connection allows multiple clients to be kept in sync
This means that content data will be stored on the Synchrony service and the service will act as the source of truth for page content. While this is the case, Confluence will continue storing a snapshot of the most recent state of the document being edited at regular intervals. This content is stored as the body content in the shared draft but shouldn't be referenced as the most up-to-date content, as changes stored in Synchrony may not have been saved to the draft yet.
How the Synchrony Service runs in Confluence Server
Synchrony is executed as a separate process by Confluence Server. This process is managed by Confluence automatically, and through out normal operations, is not intended to be managed manually by an administrator. Administrators can choose to change the editing mode (on, limited, off). The affect of this change is site-wide. Collaborative editing cannot be turned on or off for specific spaces or pages.
The Synchrony Service executable is extracted from Confluence into the home directory. It will be named '
synchrony-standalone.jar', and a second java process will be spawned with the above mentioned
jar as the entry point. Confluence passes all required parameters for Synchrony via environmental variables - these are not considered api, and may be subject to change.
Synchrony requires a JDBC connection to the database that Confluence Server runs under. The three database tables used by Synchrony are 'Events', 'Secrets' and 'Snapshots'. Modifying the contents of these tables is not recommended, and they are subject to change without notice.
The Synchrony API
Synchrony doesn't currently provide an API for third party plugins. A client-side implementation is already provided by the Confluence Collaborative Editor Plugin, which will:
- Automatically open a session to Synchrony when the Confluence editor is opened
- Propagate changes to Synchrony when page content is changed outside of the editor (see our explanation of external changes)
The Synchrony Whitelist
When a session is opened to Synchrony, a whitelist of styles, elements and attributes is provided. The whitelist prevents malicious content from being synchronised from one client to another. Any items not in the whitelist will be ignored and won't be synchronised to other editing sessions.
What happens if Synchrony is disabled?
Depending on how Synchrony is disabled:
- If Synchrony is temporarily offline, users can still edit their content but are prevented from publishing. All changes are buffered; once Synchrony comes back online, buffered changes will be merged and synchronised between clients.
- If Synchrony is unavailable for an extended time, the administrator can change the collaborative editing mode to limited, which prevents more than one person editing a shared draft at a time. This prevents any merge conflicts and data loss while Synchrony is unavailable.
As Confluence opens a WebSocket connection to Synchrony, all Synchrony traffic can be monitored in the WebSocket request via the developer tools' Network tab:
Things to test
- Make sure changes are properly persisted to Synchrony. For example, plugins that display a preview in the editor should make sure that this is updated accordingly.
- Make sure style and attribute changes aren't filtered out by the whitelist.
What are external changes?
External changes refer to updates made to page content outside of the Confluence editor, like inline comments and tasks. When external changes are made, the changes need to be propagated to Synchrony to ensure that Confluence and Synchrony are in sync.
External changes can be triggered in a number of ways. A plugin can:
- Make a request to the Confluence REST API
- Call the
- Call the
How do external changes work?
Synchrony provides an API that allows external applications to inform Synchrony of external changes. Confluence automatically makes a call to the Synchrony API whenever page content is updated, so plugins should avoid calling the Synchrony API directly.
How are external changes triggered?
The external changes call to the Synchrony API will be made from
If page updates are made which bypass the
PageManager, then updates won't be synchronised to Synchrony.
What external changes will be pushed to Synchrony?
Changes to the following will be propagated to Synchrony:
- Page title
- Body contents
Triggered after an external change has occurred and the changes have been synchronised to the editor
Also triggered once after the content in the editor is initialised by Synchrony.
Things to test
- Any changes to page contents without interacting with the editor. Make sure the change is still present when the page is edited then published.
Things you shouldn't do
- Cache a DOM reference in the plugin JS – Synchrony will perform a replacement and render the reference obsolete. Use a selector instead.
- Use the
ContentEntityManagerto directly modify page content – the external changes call will be bypassed. Always use the
Test Scenario Checklist
- Test plugins with two open tabs, as this forces the synchronised changes to be filtered by the whitelist.
- Test that external changes are correctly propagated by triggering another publish from the shared draft after the external change is made. This is to check that the change is still there after the publish.