> ## Documentation Index
> Fetch the complete documentation index at: https://docs.modulex.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Realtime collaboration walkthrough

> A hands-on walkthrough: invite a teammate to your organization, co-edit the same workflow canvas live with presence and node locks, and resolve an edit conflict the way ModuleX does it for you.

export const MediaEmbed = ({id, type = 'screenshot', caption = '', ext, ratio = '16 / 9'}) => {
  const isVideo = type === 'video' || type === 'app_video';
  const resolvedExt = ext || (isVideo ? 'mp4' : type === 'screenshot' ? 'webp' : 'svg');
  const src = 'https://media.modulex.dev/' + id + '.' + resolvedExt;
  const [status, setStatus] = useState('loading');
  const [isDev, setIsDev] = useState(false);
  const [inView, setInView] = useState(false);
  const boxRef = useRef(null);
  useEffect(() => {
    if (typeof window === 'undefined') return;
    const h = window.location.hostname;
    setIsDev(h === 'localhost' || h === '127.0.0.1' || h.endsWith('.mintlify.app'));
  }, []);
  useEffect(() => {
    if (inView) return;
    if (typeof IntersectionObserver === 'undefined') {
      setInView(true);
      return;
    }
    const el = boxRef.current;
    if (!el) return;
    const io = new IntersectionObserver(entries => {
      if (entries.some(e => e.isIntersecting)) {
        setInView(true);
        io.disconnect();
      }
    }, {
      rootMargin: '300px'
    });
    io.observe(el);
    return () => io.disconnect();
  }, [inView]);
  if (status === 'missing') {
    if (!isDev) return null;
    return <div style={{
      display: 'flex',
      flexDirection: 'column',
      justifyContent: 'center',
      gap: '0.4rem',
      padding: '1rem 1.25rem',
      margin: '1.25rem 0',
      width: '100%',
      aspectRatio: ratio,
      boxSizing: 'border-box',
      border: '1px dashed rgba(128,128,128,0.45)',
      borderRadius: '0.75rem',
      background: 'rgba(128,128,128,0.06)',
      color: 'currentColor',
      fontSize: '0.85rem',
      lineHeight: 1.45
    }}>
        <div style={{
      display: 'flex',
      alignItems: 'center',
      gap: '0.5rem',
      opacity: 0.75
    }}>
          <span aria-hidden="true">🎬</span>
          <code style={{
      fontSize: '0.75rem'
    }}>{id}</code>
          <span style={{
      fontSize: '0.65rem',
      textTransform: 'uppercase',
      letterSpacing: '0.04em',
      padding: '0.1rem 0.4rem',
      borderRadius: '0.4rem',
      background: 'rgba(128,128,128,0.18)'
    }}>
            {type}
          </span>
        </div>
        <div style={{
      opacity: 0.9
    }}>{caption || 'Media not uploaded yet.'}</div>
        <div style={{
      fontSize: '0.7rem',
      opacity: 0.5
    }}>
          Upload to R2 as <code>{id}.{resolvedExt}</code> — preview only, hidden in production.
        </div>
      </div>;
  }
  const mediaStyle = {
    display: status === 'loaded' ? 'block' : 'none',
    width: '100%',
    height: 'auto',
    borderRadius: '0.75rem'
  };
  const media = isVideo ? <video src={inView ? src : undefined} autoPlay loop muted playsInline preload="metadata" onLoadedData={() => setStatus('loaded')} onError={() => setStatus('missing')} style={mediaStyle} /> : <img src={inView ? src : undefined} alt={caption} onLoad={() => setStatus('loaded')} onError={() => setStatus('missing')} style={mediaStyle} />;
  return <figure style={{
    margin: '1.25rem 0'
  }}>
      <div ref={boxRef} style={status === 'loaded' ? {
    width: '100%'
  } : {
    width: '100%',
    aspectRatio: ratio,
    borderRadius: '0.75rem',
    background: 'rgba(128,128,128,0.06)'
  }}>
        {media}
      </div>
      {status === 'loaded' && caption ? <figcaption style={{
    marginTop: '0.5rem',
    textAlign: 'center',
    fontSize: '0.85rem',
    opacity: 0.7
  }}>
          {caption}
        </figcaption> : null}
    </figure>;
};

This walkthrough takes you through building together in ModuleX from end to end: you invite a teammate into your organization, you both open the same workflow, you co-edit it live, and you watch ModuleX handle an edit conflict on its own. By the end you will know what every cursor, avatar, and badge on the canvas means.

It is the practical, do-it-yourself companion to two reference pages. For the product tour of what co-editing looks like, see [Canvas collaboration](/platform/collaboration/canvas). For the wire-level detail behind presence, locks, and the conflict model, see [Presence, locks & versioning](/realtime/presence-locks).

<MediaEmbed id="MX-MEDIA-4410" type="app_video" caption={"The full walkthrough end to end: invite a teammate, both open the same workflow, co-edit live, then a conflict resolves itself."} />

## What you will do

<Steps>
  <Step title="Invite a teammate">
    Add a person to your organization by email so they can open the same workflows you can.
  </Step>

  <Step title="Open the same workflow">
    You and your teammate both open one workflow in the builder and join the same live canvas.
  </Step>

  <Step title="Co-edit live">
    Move nodes, add steps, and edit configuration while seeing each other's cursors and node locks in realtime.
  </Step>

  <Step title="Resolve a conflict">
    Watch what happens when two edits collide, and learn how ModuleX reconciles them for you.
  </Step>
</Steps>

## Before you start

<CardGroup cols={2}>
  <Card title="An organization you administer" icon="building">
    You invite teammates into an [organization](/concepts/organizations-roles). Only an organization **owner** or **admin** can send invitations.
  </Card>

  <Card title="A workflow to share" icon="diagram-project">
    Have at least one workflow saved in the [Workflow Builder](/workflow-builder/overview). Everyone in the organization can open it.
  </Card>

  <Card title="A teammate's email" icon="at">
    You invite by email address. Your teammate signs in (or signs up) with that email to accept.
  </Card>

  <Card title="Two browser sessions to follow along" icon="browsers">
    To see live co-editing yourself, open the workflow in two windows signed in as two different people.
  </Card>
</CardGroup>

## Step 1 — Invite a teammate

People collaborate inside an **organization**. Adding a teammate to your organization is what gives them access to your shared workflows.

<Steps>
  <Step title="Open your organization's members">
    Go to your organization settings and open the members area. You see this only if you are an **owner** or **admin** of the organization.
  </Step>

  <Step title="Send an invitation by email">
    Enter your teammate's email address and send the invitation. New teammates are added with the **admin** role.

    <Note>
      ModuleX organizations have two roles: **owner** and **admin**. The older `member` role has been retired, so an invited teammate joins as an admin. See [Roles & permissions](/security/roles-permissions) for what each role can do.
    </Note>
  </Step>

  <Step title="Your teammate accepts the invitation">
    Your teammate opens the invitation link and accepts it while signed in with the invited email address. If they are not signed in yet, the link prompts them to sign in or sign up first, then completes the acceptance.

    <Accordion title="If they sign in with the wrong account">
      Acceptance is tied to the invited email address. If your teammate is signed in with a different account, ModuleX tells them which account the invitation was sent to so they can switch to the right one and try again.
    </Accordion>
  </Step>

  <Step title="They switch to the shared organization">
    After accepting, your teammate selects the organization from the organization switcher. Everything they do from then on is scoped to that organization, and your shared workflows become visible to them.

    <Note>
      A freshly accepted role can take up to a few minutes to take effect on the live collaboration server, which caches membership briefly. If a brand-new teammate cannot edit immediately, have them refresh after a minute.
    </Note>
  </Step>
</Steps>

<MediaEmbed id="MX-MEDIA-4411" type="screenshot" caption={"The organization members screen with the invite-by-email field."} />

## Step 2 — Open the same workflow

Now both of you open the same workflow so you share one live canvas.

<Steps>
  <Step title="Both open the workflow in the builder">
    Each person opens the workflow from the [Workflow Builder](/workflow-builder/overview) list. Opening a workflow joins you to its live collaboration room automatically — there is no separate "start collaborating" button.
  </Step>

  <Step title="Confirm you are both in the room">
    When your teammate joins, their **presence avatar** appears in the canvas, and you appear on theirs. Each person is assigned a color that is used consistently for their avatar, their cursor, and any node they are editing.
  </Step>
</Steps>

<Note>
  You do not save and reload to see each other's work. Everyone is editing the **same live graph**, so changes appear as they happen. There are no separate copies to merge later. For the full picture of the two realtime planes (live canvas editing versus run streaming), see [Realtime & collaboration model](/concepts/realtime-model).
</Note>

## Step 3 — Co-edit live

With both of you in the same workflow, you can build together. Here is what you will see, and what each signal means.

### Presence and cursors

<CardGroup cols={2}>
  <Card title="Presence avatars" icon="users">
    Everyone currently in the workflow shows up as a colored avatar. When someone leaves or closes the tab, their avatar disappears.
  </Card>

  <Card title="Live cursors" icon="arrow-pointer">
    You see your teammate's cursor move across the canvas in their assigned color, so you always know where their attention is.
  </Card>

  <Card title="Away status" icon="moon">
    If a teammate stops interacting for a while, they are shown as **Away** rather than dropping off entirely. They come back to active as soon as they interact again.
  </Card>

  <Card title="Consistent colors" icon="palette">
    A person's color is the same for their avatar, cursor, and edit badge, so it is easy to tell at a glance who is doing what.
  </Card>
</CardGroup>

### Editing nodes safely with locks

To stop two people from editing the same node at the same instant, ModuleX uses **node locks**.

<Steps>
  <Step title="Open a node to edit it">
    When you open a node in the [Detail Panel](/workflow-builder/canvas) to change its configuration, ModuleX claims a lock on that node for you.
  </Step>

  <Step title="Teammates see the node is held">
    While you hold the lock, your teammates see that node marked as being edited by you, in your color. If they try to open it, ModuleX tells them who is currently editing it instead of letting them collide with you.
  </Step>

  <Step title="The lock releases when you are done">
    Your lock releases when you finish editing the node. It also releases automatically if you leave the workflow or disconnect, and it expires on its own after a few minutes of being held, so a node never stays stuck if someone closes their laptop mid-edit.
  </Step>
</Steps>

<Note>
  Locks apply to **editing one node's configuration**. Moving nodes around the canvas, adding new nodes, and connecting edges are not locked — those changes simply broadcast to everyone live. The lock exists to protect the inside of a node while one person has it open.
</Note>

### What broadcasts live

Most edits flow to everyone in the room as you make them:

<CardGroup cols={2}>
  <Card title="Adding and deleting nodes" icon="plus">
    A node your teammate adds appears on your canvas moments later, already in place.
  </Card>

  <Card title="Moving nodes" icon="arrows-up-down-left-right">
    Dragging a node to a new position updates it for everyone, so the layout stays in sync.
  </Card>

  <Card title="Connecting steps" icon="link">
    New edges between nodes show up for the whole room as they are drawn.
  </Card>

  <Card title="Node configuration" icon="sliders">
    Configuration changes save to the shared workflow and reach your teammates once the editor finishes with the node.
  </Card>
</CardGroup>

<MediaEmbed id="MX-MEDIA-4412" type="app_video" caption={"Two teammates co-editing one canvas, showing cursors, a node move, and a node lock."} />

## Step 4 — Resolve a conflict

Because everyone edits the same live graph, ModuleX keeps every collaborator on the same version. Most of the time this is invisible — edits stream back and forth and stay in order. Occasionally two people make changes so close together, or one person's connection lags far enough behind, that their version of the workflow has drifted from the shared one. That is a **conflict**, and ModuleX resolves it for you.

### What you will see

<Steps>
  <Step title="A short notice appears">
    The person whose edits fell behind sees a brief notice that their changes conflicted and the workflow is reloading.
  </Step>

  <Step title="Their canvas reloads to the latest version">
    ModuleX pulls the current shared version of the workflow and shows it. The other collaborators are unaffected — they keep working.
  </Step>

  <Step title="Everyone is back in sync">
    After the reload, both people are looking at the same up-to-date graph, and editing continues normally.
  </Step>
</Steps>

<Note>
  You do not resolve a conflict by hand and there is no "accept mine / accept theirs" prompt. ModuleX always reconciles by reloading the behind collaborator to the latest shared version. The reliable way to avoid losing in-progress edits to a single node is to use the node lock: hold the node while you edit it, and your teammates will not edit it underneath you.
</Note>

<Accordion title="Why does a conflict reload instead of merging?">
  ModuleX tracks a version number for the live workflow and advances it on every accepted edit. If a collaborator's edits arrive while their version has drifted too far behind the shared one, ModuleX cannot safely apply them in place, so it reloads that person to the current version rather than risk applying a stale change. Locking a node before you edit its configuration keeps your work safe while you have it open. The exact version and conflict mechanics are documented on [Presence, locks & versioning](/realtime/presence-locks).
</Accordion>

### Changes from Composer or the API

Not every change to a workflow comes from a person dragging nodes. The [AI Composer](/workflow-builder/composer) can rewrite the graph, and so can changes made elsewhere. When that happens while you have the workflow open, those edits **sync into your open canvas live** so you are always looking at the current version — you do not have to reload to pick them up. See [Realtime co-editing & external sync](/workflow-builder/realtime-coediting) for how that external sync works.

## A few things to know

<AccordionGroup>
  <Accordion title="Do I need an API key for any of this?">
    No. Live co-editing happens entirely inside the ModuleX web app, which signs you in with your account session. There is no REST endpoint or SDK method for presence, cursors, or locks — they exist only on the live collaboration connection the app makes for you. API keys (`mx_live_*`) are for running workflows programmatically; see [Authentication](/api-reference/authentication).
  </Accordion>

  <Accordion title="How many people can edit at once?">
    Everyone in your organization who opens the same workflow joins the same live room and can edit together. There is no separate per-workflow collaborator list — organization membership is what grants access.
  </Accordion>

  <Accordion title="What happens to my locks if I close my laptop?">
    Any node locks you hold are released automatically when you leave the workflow or disconnect, and they also expire on their own after a few minutes. A node never stays locked because someone walked away.
  </Accordion>

  <Accordion title="My teammate accepted but cannot edit yet">
    The live collaboration server caches organization membership for a short time. A brand-new teammate may need to wait a minute and refresh before their edit access takes effect. See [Account & access — Help](/help/account-access).
  </Accordion>
</AccordionGroup>

## Where to go next

<CardGroup cols={3}>
  <Card title="Canvas collaboration" icon="object-group" href="/platform/collaboration/canvas">
    The product tour of what co-editing looks and feels like.
  </Card>

  <Card title="Presence, locks & versioning" icon="lock" href="/realtime/presence-locks">
    The wire-level reference: every event, payload, timing, and edge case.
  </Card>

  <Card title="Build a workflow with Composer" icon="wand-magic-sparkles" href="/guides/build-with-composer">
    Go from a plain-English prompt to a running workflow.
  </Card>
</CardGroup>
