# Transports

A *transport* is a client-side interface that can connect to a comms URI and exchange real-time messages with peers or services.

{% hint style="info" %}
You can see the comms protocol in action and experiment with it using the open-source [Comms Station](https://decentraland.github.io/comms-station/).
{% endhint %}

Clients are free to implement transports as they see fit (as long as they follow the protocol expected by other clients and services), but the [recommended design](#recommended) described below has been tested in practice and proven to integrate well with different projects.\`

### Standard Transports <a href="#types" id="types"></a>

There are 5 transport types defined by the protocol:

* [Websocket](https://github.com/decentraland/docs/blob/main/contributor/communications/transport-types/websocket/README.md) (`ws-room`) uses a standard websocket stream.
* [LiveKit](https://github.com/decentraland/docs/blob/main/contributor/communications/transport-types/livekit/README.md) (`livekit`) uses the open-source LiveKit framework, based on WebRTC.
* [SignedLogin](https://github.com/decentraland/docs/blob/main/contributor/communications/transport-types/signed_login/README.md) (`signed-login`) makes a signed HTTPs request to obtain a dynamically assigned transport from a server.
* [Offline](https://github.com/decentraland/docs/blob/main/contributor/communications/transport-types/offline/README.md) (`offline`) is a dummy transport indicates there are no comms in the current environment.
* [Simulator](https://github.com/decentraland/docs/blob/main/contributor/communications/transport-types/simulator/README.md) (`simulator`) is a dummy transport with completely custom behavior, mainly for developers to debug their implementations.

Messages sent and received through a transport interface are always the same (see [messages](https://github.com/decentraland/docs/blob/main/contributor/communications/messages/README.md)). Some transports may wrap them in control structures for transmission, but these should be unpacked before crossing the `Transport` interface.

### Recommended Design <a href="#recommended" id="recommended"></a>

This is a minimal `Transport` interface written in TypeScript:

```ts
interface Transport {
  // Initialize the Transport with a URI:
  constructor(private uriWithConnectionParams: string)

  // Open a connection using the URI given in the constructor:
  connect(): Promise<void>

  // Close the connection:
  disconnect(): Promise<void>

  // Send an arbitrary payload to the service and all peers:
  send(packet: Packet): Promise<void>

  // Subscribe to incoming messages from both the service and all peers:
  on(event: 'receive', callback: (packet: Packet) => void): void
}
```

Actual implementations commonly extend this, adding connection/disconnection and join/leave events, non-broadcast sending, stricter typing or language-specific adaptations.

#### Transport URIs

The values of `uriWithConnectionParams` are always of the form:

```
<type>:<type connection parameters>
```

The `<type>` corresponds to one listed above, and the format for `<type connection parameters>` is dependent on the specific transport. It can be a URL, an opaque token, or any arbitrary data.

The [LiveKit](https://github.com/decentraland/docs/blob/main/contributor/communications/transport-types/livekit/README.md) transport, for example, uses a `wss` URL with an `access_token` parameter to establish an authenticated connection:

```
livekit:wss://comms.example.com?access_token=eyJhbGciOiJI...
```

For comparison, the [Websocket](https://github.com/decentraland/docs/blob/main/contributor/communications/transport-types/websocket/README.md) transport also uses a `wss` URL, but without a pre-generated token. It requires an authentication flow once connected.

#### Creating Transports

Since each `Transport` class will support a particular kind of URI, it's a good idea to have a factory method that either returns a valid `Transport` or fails immediately. For example:

```ts
function createTransport(uriWithConnectionParams: string) {
  const type = getPrefix(urlWithConnectionParams)

  switch (type) {
    case 'ws-room': return new WsRoomTransport(uriWithConnectionParams)
    case 'livekit': return new LiveKitTransport(uriWithConnectionParams)
    // ... other supported implementations...
  }

  throw new Error(`Unsupported transport type: ${type}`)
}
```

Clients are not required to implement all standard transports. If they intend to only use a subset of the defined types without aiming to handle all URIs, they are free to reject types they don't support.

More featured clients, such as a World Explorer, are advised to implement at least the [websocket](https://github.com/decentraland/docs/blob/main/contributor/communications/transport-types/websocket/README.md) and [LiveKit](https://github.com/decentraland/docs/blob/main/contributor/communications/transport-types/livekit/README.md) transports, which are currently in use by all major realms.

### Learn more

Head over to a [specific transport type](#types) section, read about the different [message types](https://github.com/decentraland/docs/blob/main/contributor/communications/messages/README.md) or check out the \[\[Comms Demo Station]].


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.decentraland.org/contributor/communications/transports.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
