Skip to main content

WebSocket Sync

Notify connected applications when your project changes. Edit in StoryFlow Editor, and your game engine or custom tool picks up the updates automatically.

What is WebSocket Sync?

WebSocket Sync is a real-time synchronization method that lets StoryFlow Editor notify connected clients when project data has been updated. When a sync is triggered, the editor exports your project as JSON and sends a WebSocket notification to all connected applications, telling them where to find the updated files. This happens as soon as you click Sync — or automatically when a connected client requests it.

This is the foundation for live-editing workflows: you make changes in StoryFlow Editor, the export and notification happen automatically, and your game engine or tool picks up the updated files without you having to manually re-export and re-import.

Perfect For

  • Live iteration with game engines during development
  • Previewing dialogue changes without restarting your game
  • Building custom tools that react to project updates in real time
  • Automated pipelines that trigger on project changes

Official Plugin Support

The Unreal Engine plugin has built-in support for WebSocket Sync — no manual protocol implementation needed. For other engines or custom tools, this page describes the protocol so you can build your own client.

How It Works

The synchronization flow has three parts:

  1. Server — StoryFlow Editor runs a WebSocket server on a configurable port (default 9000). Clients connect to this server.
  2. Export — When a sync is triggered, the editor saves all changed files, performs a JSON export, and broadcasts a notification to all connected clients.
  3. Client pickup — Connected clients receive the notification, read the exported JSON files from disk, and re-import the project data.

JSON Export Under the Hood

WebSocket Sync uses the same JSON export pipeline as the standalone JSON export. The exported files are written to the project's build/ directory, and the WebSocket message tells clients where to find them. This means clients need access to the same file system as the editor.

Starting the Server

To start the WebSocket server:

  1. Click the dropdown arrow on the Export split button in the top-right corner of the editor
  2. Select WebSocket as the export format
  3. The main button changes to Start Server — click it
  4. The server starts listening for connections on the configured port

Once the server is running, the button changes to Sync with a green status indicator. The indicator also shows the number of connected clients. The dropdown displays details for each connected client, including engine name, engine version, and plugin version. You can disconnect individual clients from the dropdown.

To stop the server, open the dropdown again and click Stop Server.

Syncing Your Project

There are two ways to trigger a sync:

From the editor:

  1. With the server running, click the Sync button
  2. The editor saves all unsaved files, exports JSON, and notifies connected clients
  3. A toast notification shows whether the sync was delivered to clients

From a connected client:

  1. The client sends a request-sync message over the WebSocket connection
  2. The editor receives the request, saves all unsaved files, exports JSON, and broadcasts the update

Both methods produce the same result: all changed files are saved first, then the project is exported and clients are notified.

Port Configuration

The default port is 9000. To change it:

  1. Open the export dropdown
  2. Select WebSocket
  3. Edit the Port field (valid range: 1024–65535)
  4. The port is saved and persists between sessions

Port Must Match

The port configured in StoryFlow Editor must match the port your client connects to. If you change the port in the editor, update your client configuration accordingly.

The port field is disabled while the server is running. Stop the server before changing the port.

Connection Protocol

The WebSocket server uses a simple JSON-based message protocol. All messages are JSON objects with a type field and an optional payload field.

Message Format

JSON
{
  "type": "message-type",
  "payload": {
    "key": "value"
  }
}

Client to Editor

Messages that clients can send to the editor:

  • connect — Handshake message sent after connecting. Identifies the client to the editor.
    JSON
    {
      "type": "connect",
      "payload": {
        "engine": "Unreal Engine",
        "version": "5.5",
        "pluginVersion": "1.0.0"
      }
    }
  • request-sync — Asks the editor to save all files, export the project, and broadcast the update to all connected clients.
    JSON
    {
      "type": "request-sync"
    }
  • ping — Keep-alive message. The editor responds with pong.
    JSON
    {
      "type": "ping"
    }

Editor to Client

Messages that the editor sends to clients:

  • project-updated — Broadcast to all clients after a successful sync. Contains the project path so the client knows where to find the exported files.
    JSON
    {
      "type": "project-updated",
      "payload": {
        "projectPath": "C:/Users/you/Documents/MyProject"
      }
    }
  • pong — Response to a ping message.
    JSON
    {
      "type": "pong"
    }

Building a Custom Client

If you're building your own integration (for a custom engine, tool, or pipeline), here's the typical flow:

  1. Open a WebSocket connection to ws://localhost:9000 (or your configured port)
  2. Send a connect message to identify your client
  3. Optionally send request-sync to get an initial sync
  4. Listen for project-updated messages
  5. When received, read the exported JSON files from {projectPath}/build/
  6. Send periodic ping messages to keep the connection alive

Here's a minimal example in Python:

Python
import asyncio
import websockets
import json

async def sync_client():
    uri = "ws://localhost:9000"
    async with websockets.connect(uri) as ws:
        # Identify ourselves
        await ws.send(json.dumps({
            "type": "connect",
            "payload": {
                "engine": "My Custom Tool",
                "version": "1.0"
            }
        }))

        # Request initial sync
        await ws.send(json.dumps({"type": "request-sync"}))

        # Listen for updates
        async for message in ws:
            data = json.loads(message)
            if data["type"] == "project-updated":
                project_path = data["payload"]["projectPath"]
                print(f"Project updated at: {project_path}")
                # Read files from {project_path}/build/
                # ... your import logic here

asyncio.run(sync_client())

Troubleshooting

Port already in use

If the server fails to start with a "port in use" error, another application is using that port. Either close the other application or change the port in the export dropdown.

No clients connected

If you click Sync and see "No Clients Connected", make sure your client application is running and connected to the correct port. Check the green status indicator next to the Sync button — it shows the number of active connections.

Client not receiving updates

Verify the client is listening for project-updated messages. Ensure the WebSocket connection hasn't dropped — use ping/pong messages to keep it alive.

Files not found after sync

The projectPath in the project-updated message points to the project root. Exported files are in the build/ subdirectory. Ensure the client has read access to this path.

Next Steps

See the Game Engine Integration page for engine-specific setup, or check the Unreal Engine Live Sync guide for a complete walkthrough of the built-in plugin integration.

Need Help?

Join our Discord community to ask questions, share your projects, report bugs, and get support from the team and other users.

Join Discord