Client Messaging

Application extensions and the Onshape JavaScript web client need to communicate directly, calling across the iframe containing the application extension using post message. image alt text

Client message structure

The basic client message structure is:

clientMessage = {
    documentId: documentId,
    workspaceId: workspaceId,
    elementId: elementId,
    messageName: string
};

Where messageName corresponds to one of the supported client messages for the extension type. To view the supported client messages for each extension type, see:


Security considerations

To ensure security, an application extension must:

  • Parse for document, workspace, and element IDs: Parse for the documentId, workspaceId, and elementId that were passed as query parameters within the application extension’s iframe src URL. You must post these back in each POST message.
  • Parse for the server: Parse for the server that was passed as a query parameter within the application extension’s iframe src URL. You must use this to validate messages received.
    • If the application extension uses a JavaScript library or framework (e.g., BackboneJS or AngularJS), it can parse the query parameters and maintain state in other ways.
  • Not redirect to another base URL: The browser tells the Onshape client the origin base URL from which a POST message is received. The Onshape client ignores messages posted from an origin URL that doesn’t match the original iframe src URL. It is extremely important to the security of your application that you verify that the origin of all messages you receive is the same as the original server query parameter in the iframe src (i.e., if (server === e.origin)). In production operation especially, the message IS NOT SAFE if the message origin does not match the iframe src server query parameter. Application extensions should not redirect to another base URL after the iframe has been opened, or the messages will be ignored.
  • Post a message on startup: Onshape will not post messages until a newly started application extension has first posted a valid message to Onshape. This constraint is in effect anytime an application extension is (re)started and exists to avoid posting messages to application extensions that are not ready to handle them, are not fully loaded, etc. After your application extension is fully loaded and ready to receive messages, post a message to Onshape. A keepAlive message is a great first message to send to Onshape. Once Onshape receives a valid message, Onshape will start posting messages to the application extension. If the application extension later sends an invalid message Onshape will stop sending messages until a valid message is posted to Onshape.

POST messages submitted by application extensions to Onshape will be ignored if any of the following are true:

  • The documentId, workspaceId, or elementId are missing or not valid.
  • The message name is missing or not recognized.
  • The origin of the POST message does not match the original iframe src URL.

Code snippets

Parse query parameters

This JavaScript code parses the iframe src parameters and uses them to post a message:

 /**
 * Extracts Onshape document, workspace, and element IDs from a given URL.
 * Supports both query parameter format and Onshape path-based URL format.
 *
 * @param {string} currentURL - The full URL string to parse.
 * @returns {{ documentId: string, workspaceId: string, elementId: string }} An object containing the three Onshape IDs.
 * @throws {Error} If the required IDs cannot be found in the URL.
 */
function getOnshapeIdsFromUrl(currentURL) {
    const url = new URL(currentURL);
    const params = url.searchParams;

    const documentId = params.get('documentId');
    const workspaceId = params.get('workspaceId');
    const elementId = params.get('elementId');

    if (documentId && workspaceId && elementId) {
        return { documentId, workspaceId, elementId };
    }

    const pathMatch = url.pathname.match(/\/documents\/([^/]+)\/(?:w|v|m)\/([^/]+)\/e\/([^/]+)/);

    if (pathMatch) {
        return {
            documentId: pathMatch[1],
            workspaceId: pathMatch[2],
            elementId: pathMatch[3]
        };
    }

    throw new Error('Missing Onshape IDs in URL. Provide documentId, workspaceId, and elementId as query parameters or use an Onshape document URL.');
}

Create a message object

The message object posted to the Onshape client is of the form:

{
    documentId: documentId,
     workspaceId: workspaceId,
     elementId: elementId,
     messageName: '<message name>',
    // … other properties as needed for other message types …
}

The message data object posted to the application extension is of the form:

{
    messageName: '<message name>',
 //    … other properties as needed for other message types …
}

The message will always have a messageName property.

Listen for messages

To listen for messages from the Onshape client:

  // server is one of the iframe src query parameters - see above

  var handlePostMessage = function(e) {
    console.log("Post message received in application extension.");
    console.log("e.origin = " + e.origin);

    // Verify the origin matches the server iframe src query parameter
    if (server === e.origin) {
      console.log("Message safe and can be handled as it is from origin '"
                  + e.origin +
                  "', which matches server query parameter '"
                  + server + "'.");
      if (e.data && e.data.messageName) {
        console.log("Message name = '" + e.data.messageName + "'");
      } else {
        console.log("Message name not found. Ignoring message.");
      }
    } else {
      console.log("Message NOT safe and should be ignored.");
    }
  };

  window.addEventListener('message', handlePostMessage, false);

Send and handle messages

The following is an example of how one might send an initialization message to, and handle post messages from, the Onshape client.

Note: Proper clean-up of event listeners is not included in the snippet

function handlePostMessage(event) {
  // ensure that the event data is from a legit source:
  if(theServerStringFromActionUrl !== event.origin) {
    console.error('origin of message is not legitimate');
    return;
  }

  // branch based on messageName attribute
  switch(event.data.messageName) {
    case 'SELECTION':
      console.debug('SELECTION event data: %o', event.data);
      break;
    default:
      console.debug(`${event.data.messageName} not handled`);
    }
}

window.addEventListener('message', handlePostMessage);

const initMessage = {
  documentId:  theDocumentId,    // required - parsed from action url
  workspaceId: theWorkspaceId,   // required - parsed from action url
  elementId:   theElementId,     // required - parsed from action url
  messageName: 'applicationInit' // required
};

window.parent.postMessage(initMessage, '*');

Notes

  • Keyboard focus will not be transferred to an application until the user clicks in the application or the application programmatically takes focus. An application should programmatically take focus when it is first loaded and when it receives a show message from Onshape. Shortcut keys will work immediately when the application is shown.
  • New message types will be added as needed. If your application extension needs a message not listed in this document, please notify us, and we’ll work with you on it.
  • Mobile clients are currently not supported.