Updating prosemirror doc from an external (non prosemirror) yjs update

Hello hello,

Firstly thanks for this wonderful library.

I am trying to use prosemirror in this manner:

  1. I have a UI where a user selects some items, let’s assume they’re images.
  2. I have a prosemirror (actually blocknote which is based on tiptap which is based on pm) doc open with collaboration on.
  3. I have custom blocks set up for displaying the above charts. Charts created from within the prosemirror docs work and display fine with no problems. Collaboration works too.

I am trying to do this:

  1. When the user selects a chart on the UI, I connect to the yjs provider for the doc.
  2. I get the current state of the doc after yjs’s sync event is called. I get the latest state which appears to be correct upon checking.
  3. I add an xmlelement to the yjs doc containing the necessary info to render the custom chart: Basically an image path as a prop which I can later fetch from a db.

My expectation is that this change should show up immediately on the prosemirror doc which is listening(?) to changes on the yjs doc.

But something weird seems to happen. On the page where the prosemirror doc is displayed, I tried logging from inside the the yjs doc’s update event and got this:

  1. Initially I get the correct updated state of the doc with the new image at the end.
  2. But then, a few logs later and before pm can even flush that new state to the actual doc, I get more logs showing the state going back to the initial state of the doc without that image.
  3. I am just using the doc.toJSON method for checking yjs state.

I’m wondering what I’m doing wrong? Is it even possible to update the prosemirror doc in this manner? Or if there’s something in the transaction I can add which makes it not revert?

Here’s some snippets:

  1. This is the function I’m using to add an element to the doc:
export function appendImageToYjsDoc(yjsDoc, imagePath) {
  const newBlock = createNewYjsXmlElement("blockcontainer", {
    id: v4(),
    backgroundColor: "default",
    textColor: "default",
  const newImage = createNewYjsXmlElement("chart-image", {
    imagePath: imagePath,
  newBlock.insert(0, [newImage]);

  yjsDoc.transact((tr) => {
    const blockGroup = yjsDoc.getXmlFragment("document-store").firstChild;

    blockGroup.insert(blockGroup.length, [newBlock]);
  1. Here’s my YPartykitProvider setup on the blocknote end:
const yjsDoc = new Y.Doc();
const yjsProvider = new YPartyKitProvider(partyEndpoint, docId, yjsDoc, {
    params: {
      doc_id: docId,
    protocol: "ws",
  1. Here’s my click handler for that button:
const newDoc = new Doc();
const yjsProvider = new YPartyKitProvider(
    params: {
      doc_id: docId,
    protocol: "ws",

yjsProvider.on("sync", () => {
  appendimageToYjsDoc(yjsProvider.doc, imagePath);

bumping jic someone can help :frowning:

Why don’t you just insert from ProseMirror if that works already? Just send a transaction that inserts the PM node. What you’re doing should work IMO.