1. Overview
  2. Use cases
  3. Availabilty
  4. Demo
  5. How it works
  6. Join a session
  7. Monitor a session
  8. Versioning
  9. Custom Languages
  10. Session lifecycle and error codes
  11. Collaboration API


With Co-editing, multiple users can work on the same email or landing page simultaneously. Co-editors can see what each other is doing, as their changes are synced to the stage in real-time.


Co-editing avatars


Each user is represented by a round icon with the initial of the user, and hovering the mouse on the icon will show the full name for that user.

When a user selects a row or a content block, other co-editors will see it highlighted with that user’s color. To avoid conflicting edits, only one user at a time can edit a row or block. A feedback message will guide users when this situation happens.


Content locked by another user

Use cases

In companies, it’s rare someone works alone on everything related to email and landing pages. Your customers may have multiple people sharing duties – copywriting, design, testing, reviewing. That is why SaaS applications typically offer additional users or seats, so that more people can log into an account at the same time.

In this case, co-editing is the logical solution for an authentic teamwork experience, Google-doc style.


Co-editing + Commenting


If you add Commenting to the mix, BEE becomes an all-round, real-time collaboration solution to create emails and landing pages, unifying your customers’ workflow under one roof.


Co-editing is available for BEE Plugin Gold and Enterprise plans:

  • Gold plans are limited to a maximum of 5 co-editors per session.
  • Enterprise plans are limited to a maximum of 20 co-editors per session.

This means that, on Gold, no more than 5 users can edit the same email or web page simultaneously. Your application will only receive an error code from BEE when the limit is reached and the editor will not load – you’ll need to add a user notification to let them know they cannot join the editing session (e.g. “Sorry, you cannot edit this message because you’ve reached the limit of 5 co-editors, try again later”). Even better, you can monitor sessions and disable editing for an email or landing page once the limit is reached.


You can demo Co-editing using our Coral Demo site. This is a fictitious application, and we have created a rather simple co-editing integration. Read the technical documentation for full details on how to implement Co-editing inside your app.

At first access, the site will ask for your username. It will be saved in the browser storage, and used for your avatar during co-editing sessions.

Enter the username

In the “My Emails” section, mouse over one of the saved emails and select “Start Co-editing”.

Start co-editing in demo

When the editor loads, you will see a new “Co-edit” menu item at the top. Click on the “Co-edit” menu and then on “Copy”.

Copy co-edit link

The special URL to be used for starting the co-editing session will be copied to your clipboard. Paste that URL in a different browser window, or pass it to another person. That’s it! After entering the name, the other person will join the session and you can start co-editing.

Please note that the demo is limited to a maximum of 5 co-editors per active session.

How it works

Creating a co-edit session is nearly identical to starting a traditional, single-user session of BEE Plugin. You simply need to pass a shared flag, indicating the template is sharable, along with some simple user settings.

User settings

The following parameters are all required.

Description Type Value
username string The user’s display name
userColor string Hex color code (e.g. #FFFFFF)

Example beeConfig:

var config = {
  uid: '1234', 
  username: 'Jane Doe', 
  userColor: 'black',


The following shared parameter is required to start a co-editing session.

Description Type Value
shared boolean true or false

You pass this argument in the start instance method’s options parameter.

Example instance method when not using co-editing:


Example instance method with co-editing enabled:

bee.start(template, { shared: true })

Session started callback

Once the session is started, a globally unique id will be created and returned to the host app via the onSessionStarted callback. The host application will save this session id, and use it when users want to join the same session.

Description Type Value
sessionId string globally unique id saved from onSessionStarted callback

Example callback handler:

onSessionStarted: function(sessionInfo) {
  console.log('*** [integration] --> (onSessionStarted) ', sessionInfo)
  prompt('press ctrl+c to copy the session ID', sessionInfo.sessionId)

Join a session

The host app can join a user to any active co-edit session by using the new join instance method. The join method replaces the bee.start method and accepts the session id as a parameter, and loads the current template directly from the active session.


Monitor a session

Once the session is started, all changes to the session are reported to the onSessionChange callback. The host application can monitor this callback to understand the session’s status.

Description Type Value
change object An object containing the type of change and a value containing more details.
sessionData object An object containing useful session data, such as a list of users.

Example return JSON:

  change: { 
    type: "USER_JOINED", 
    value: {
      username: "John Doe", 
      userColor: "#c0ffee" 
      userId: "johndoe"
  sessionData: {
    users: {
      668bf8aa-97b9-4f5d-80a2-dc3e0986a370: { 
        userId: "johndoe", 
        username: "John Doe", 
        userColor: "#c0ffee" 

Example onSessionChange handler:

onSessionChange: function(data) {
  console.log('*** [integration] --> (onSessionChange) ', data)

Use cases to monitor a session

  • Only display a “join” button when a session is active
  • Display a “edit” session only if there is at least one free co-editing spot (see Availability)
  • Know when someone logs on or logs off, and notify other users in the host app
  • Know when the session contains only a single user, so the user knows it’s safe to send a campaign


During the co-edit session, the host application may receive callbacks for saving JSON and HTML. However, with multiple users editing the content, potentially all over the world, the host application needs to confirm which changes are new vs. old. For this reason, a new version parameter has been added to all of the callbacks that return JSON or HTML.

The version is a simple integration counter: 1, 2, 3, …

New onSave callback handler:

onSave: function(jsonFile, htmlFile, version) {
   console.log(`*** [integration] (onSave) version ${version}, ${new Date().toISOString()}`);

New onSaveAsTemplate callback handler:

onSaveAsTemplate: function(jsonFile, version) {
   console.log(`*** [integration] (onSaveAsTemplate) version ${version}, ${new Date().toISOString()}`);

New onSend callback handler:

onSend: function(htmlFile, version) {
   console.log(`*** [integration] (onSend) version ${version}, ${new Date().toISOString()}`);

Custom Languages

You may override any of the default language strings using custom translations.  The code block below contains the JSON required to replace all co-editing strings.

translations: {
  "mailup-bee-newsletter-collaboration": {
    "locked-module-warning-message": "This module is being edited by another user and therefore its content cannot be edited.",
    "locked-module-warning-title": "This module is locked",
    "locked-row-warning-message": "This row is being edited by another user and therefore its content cannot be edited.",
    "locked-row-warning-title": "This row is locked",
    "row-delete-confirm-title": "Are you sure you want to delete this row?",
    "row-delete-confirm-message": "Another user is currently editing a module inside this row. By deleting it, you might cause their work to be lost.",
    "lock-rejected-title": "Element was locked by another user.",
    "lock-rejected-message": "The element is currently being edited by another user. Please wait until they are finished with their changes."

Session lifecycle and error codes


Both the server and client regularly check the connection using the “ping-pong” heartbeat. 

If the client misses 5 consecutive pings (ping is emitted every 10s), the server considers the connection to be lost and disconnects the client.

If the server misses 5 consecutive pings (also every 10s), the client considers the connection to be lost and will attempt to reconnect (see below).

Reconnect mechanism

If the server disconnects without reason (the disconnection is not clean), or it misses 5 consecutive pings, the client will attempt to reconnect to the session. It will keep trying for the 60s before emitting an error with code 5400.

Reconnect mechanism is also employed after certain recoverable errors, specifically 5001, 5100 and 5300. The error itself is only emitted if the reconnect fails.

The server will wait for 60s after the last user of the session disconnects (or the connection is lost) before erasing the session data.

Error state

During reconnecting, the app is covered with an overlay to prevent the user from doing any changes (since they cannot be synchronized). This overlay also appears if the server has missed a ping.

In case of error, another overlay modal is displayed to prevent the user from interacting with the plugin in an error state. The host application should handle the errors and restart the plugin.

Error codes

You can monitor the BEE Plugin onError callback to know when a problem occurs, and then alert users of the problem.  For example, if a user loses internet connection, you can display an alert in the host app to let them know their changes have not been saved.

Here is the full list of error codes that can be returned for Co-editing.

Code Message Details Is recoverable?
5001 Unexpected error occurred during co-editing. General error. Yes
5100 Failed to open co-editing session. Unexpected error when creating/joining a co-editing session. Yes
5150 Session does not exist. The client attempted to join a non-existing (or expired) session. No
5200 Failed to synchronize changes. Emitted if an unexpected error occurs on the server during the real-time synchronization of changes. No
5300 Connection to the synchronization server was lost. The server closed the connection. Reason is given in the detail field. Yes
5400 Connection to the synchronization server was lost. Caused by network connection error or the server unexpectedly dying. No
5500 Co-editing is not supported for your current plan. If the client attempts to initiate or join a co-editing session with a lower plan. No
5600 Co-editing server is not available. Please try again later. No

Collaboration API


All API access is over HTTPS, and accessed from the following URL:{resource}

Start a session

POST /sessions

Content-Type: application/json



template object required A Bee Plugin template in JSON format


    "template": {
        "page": { ... }



    "historyEntry": {
        "version": 1,
        "timestamp": "2021-03-17T06:28:41.196Z",
        "changeId": "8c10f5d6-65b4-4b21-8143-9cb982040624",
        "label": "opened",
        "type": "settings",
        "userId": "coedit_server_init_0",
        "diff": []
    "sessionId": "a34d2a8a-605a-4ab8-b185-bc7f7700c220",
    "template": {
        "page": {

Session details

GET /sessions/{sessionId}

Content-Type: application/json



    "template": {
        "page": {
        "comments": {}
    "users": {}