---
title: Configuring Transports
slug: v4-5/transports/configuring-transports
docTags: 
createdAt: 2023-07-28T23:20:15.622Z
---

This article provides instructions on how to explicitly configure your Ditto instance to listen for connections on a specific port and to connect to remote instances using a host (IP) and port.&#x20;

:::hint{type="info"}
Although Ditto automatically attempts to connect to other instances on the Local Area Network (LAN), Bluetooth Low Energy (LE), and Apple Wireless Direct Link (AWDL), supplying a `DittoTransportConfig` does *not* enable this feature by default.&#x20;

You must manually enable peer-to-peer connections using `EnableAllPeerToPeer()`. For instructions, see [Enabling and Disabling Transports](./#enabling-and-disabling-transports).
:::

# Configuring Additional Settings

In some cases, you may need to set up additional connection configurations for the current Ditto instance. This section provides instructions on how to explicitly configure your Ditto instance to listen for connections on a specific port and to connect to remote instances using a host (IP) and port.&#x20;

To configure additional connection settings for the current Ditto instance, before calling `startSync()`, construct a `DittoTransportConfig` value and set it using `ditto.SetTransportConfig`.

# Enabling and Disabling Transports

You can enable and disable transport protocols for all connected Small Peers by doing either of the following.&#x20;

- To enable all transport protocols at once, configure `EnableAllPeertoPeer( )`.
- To enable transport protocols separately, configure a transport protocol one at a time, as shown in the following example.

:::CodeblockTabs
```swift
// Create a new DittoTransportConfig()
var config = DittoTransportConfig()

//Enable all peer to peer transports
config.enableAllPeerToPeer()

//Or enable/disable each transport separately
//BluetoothLe
config.peerToPeer.bluetoothLE.isEnabled = true
//Local Area Network
config.peerToPeer.lan.isEnabled = true
//Awdl
config.peerToPeer.awdl.isEnabled = true

ditto.transportConfig = config

do {
  try ditto.startSync()
} catch (let err) {
  print(err.localizedDescription)
}
```

```kotlin
val config = DittoTransportConfig()

//Enable all peer to peer transports
config.enableAllPeerToPeer()

//Or enable/disable each transport separately
//BluetoothLe
config.peerToPeer.bluetoothLe.enabled = true
//Local Area Network
config.peerToPeer.lan.enabled = true
//Wifi Aware
config.peerToPeer.wifiAware.enabled = true

ditto.transportConfig = config

ditto.startSync()
```

```javascript
const config = new TransportConfig()

// Enable all peer to peer transports
config.setAllPeerToPeerEnabled(true)

// or enable/disable each transport separately
// BluetoothLE
config.peerToPeer.bluetoothLE.isEnabled = true

// Local Area Network
config.peerToPeer.lan.isEnabled = true

// AWDL
config.peerToPeer.awdl.isEnabled = true

ditto.setTransportConfig(config)
ditto.startSync()
```

```java
DittoTransportConfig config = new DittoTransportConfig();

//Enable all peer to peer transports
config.enableAllPeerToPeer();

//Or enable/disable each transport separately
//BluetoothLe
config.getPeerToPeer().getBluetoothLe().setEnabled(true);
//Local Area Network
config.getPeerToPeer().getLan().setEnabled(true);
//Awdl
config.getPeerToPeer().getWifiAware().setEnabled(true);

ditto.setTransportConfig(config);

try {
    ditto.startSync();
} catch(DittoError error) {
    // handle error
}
```

```csharp
DittoTransportConfig config = new DittoTransportConfig();

//Enable all peer to peer transports
config.EnableAllPeerToPeer();

//Or enable/disable each transport separately
//BluetoothLe
config.PeerToPeer.BluetoothLE.Enabled = true;
config.PeerToPeer.BluetoothLE.Enabled = true;
//Local Area Network
config.PeerToPeer.Lan.Enabled = true;
//Awdl
config.PeerToPeer.Awdl.Enabled = true;

Ditto.TransportConfig = config;

Ditto.StartSync();
```

```cpp
// Not supported.
```

```rust
// Not supported.
```
:::

# Syncing with Big Peer

The Big Peer generates certificates automatically for each Small Peer. A certificate involves an expiration date and AppID, among other credentials. Read more here about how it works.

In order to sync with other devices, a peer must connect to the Big Peer at least once. To do this, you must use either `OnlinePlayground` or `OnlineWithAuthentication` digital identities.

We recommend using OnlinePlayground for development and OnlineWithAuthentication for production apps. If you only want to use the Big Peer for authentication without syncing to the cloud, you can use `enableDittoCloudSync=false`.

:::hint{type="info"}
By default, `enableDittoCloudSync` is set to `true`.
:::

:::CodeblockTabs
```swift
let ditto = Ditto(identity: .onlinePlayground(
    appID: "REPLACE_ME_WITH_YOUR_APP_ID",
    token: "REPLACE_ME_WITH_YOUR_PLAYGROUND_TOKEN",
    // Set to false to disable syncing with the cloud
    enableDittoCloudSync: true
))
do {
  try ditto.startSync()
} catch (let err) {
  print(err.localizedDescription)
}
```

```kotlin
val config = DittoTransportConfig()

//Enable all peer to peer transports
config.enableAllPeerToPeer()

//Or enable/disable each transport separately
//BluetoothLe
config.peerToPeer.bluetoothLe.enabled = true
//Local Area Network
config.peerToPeer.lan.enabled = true
//Wifi Aware
config.peerToPeer.wifiAware.enabled = true

ditto.transportConfig = config

ditto.startSync()
```

```javascript
const identity: Identity = {
  type: 'onlinePlayground',
  appID: 'REPLACE_ME_WITH_YOUR_APP_ID',
  token: 'REPLACE_ME_WITH_YOUR_PLAYGROUND_TOKEN',
  // Set to false to disable syncing with the cloud
  enableDittoCloudSync: true,
}
const path = './your-ditto-application-data-path'
const ditto = new Ditto(identity, path)
ditto.startSync()
```

```java
DittoIdentity identity = new DittoIdentity.OnlinePlayground(androidDependencies,
        "REPLACE_ME_WITH_YOUR_APP_ID",
        "YOUR_PLAYGROUND_TOKEN_HERE",
        // Set to false to disable syncing with the cloud
        true);

Ditto ditto = new Ditto(androidDependencies, identity);

try {
    ditto.startSync();
} catch(DittoError e) {
    //handle error
}
```

```csharp
try
{
    var ditto = new Ditto(DittoIdentity.OnlinePlayground(
        appId: "REPLACE_ME_WITH_YOUR_APP_ID",
        token: "REPLACE_ME_WITH_YOUR_PLAYGROUND_TOKEN",
        // Set to false to disable syncing with the cloud
        enableDittoCloudSync: true), path);

    ditto.StartSync();
}
catch (DittoException ex)
{
    Console.WriteLine($"Ditto Error {ex.Message}");
}
```

```cpp
// Not supported.
```

```rust
// Not supported.
```
:::

# Observing Peers​

Ditto always monitors the mesh network and can report the device names of peers it is connected to. You can manually set the device name of those peers and observe those peers in the network.

:::hint{type="info"}
The device name must be set before `startSync()` is called.
:::

:::CodeblockTabs
```swift
ditto.deviceName = "Susan B."
let observer = ditto.presence.observe { presence in
    // Render peers
}

do {
  try ditto.startSync()
} catch (let err) {
  print(err.localizedDescription)
}
```

```kotlin
ditto.deviceName = "Susan B."
ditto.startSync()
peersObserver = ditto.presence.observe { graph ->
  // Render peers
}
```

```javascript
ditto.deviceName = "Susan B."
ditto.startSync()
peersObserver = ditto.presence.observe({ graph ->
  // Render peers
})
```

```java
ditto.deviceName = "Susan B.";
try {
    ditto.startSync();
} catch(DittoError e) {
    // handle error
}
ditto.getPresence().observe(peers -> {
    // render peers
});
```

```rust
// Not supported.
```
:::

If you want to observe changes made by a particular device, include the device name as a field in the document and query for that field in your ditto live query.

:::CodeblockTabs
pseudocode

```kotlin
"status == 'open' && edited_by == 'deviceC'"
```
:::

# Connecting to Remote Small Peers

If you know the host and port of another remote Ditto peer and would like to connect to it, construct a `DittoTransportConfig` object and, using `string` format: `host:port` separated by a colon, add the host and port to the `DittoTransportConfig.Connect.TcpServers` property.&#x20;

For example, the following indicates there are two other Small Peers known to Ditto and provides details of their network locations, including the IP addresses and port numbers associated with each peer:

- Host IP `135.1.5.5` at port `12345`
- Host IP `185.1.5.5` at port `4567`

:::CodeblockTabs
```swift
var config = DittoTransportConfig()
// Connect explicitly to a remote devices
config.connect.tcpServers.insert("135.1.5.5:12345")
config.connect.tcpServers.insert("185.1.5.5:12345")

ditto.transportConfig = config

do {
  try ditto.startSync()
} catch (let err) {
  print(err.localizedDescription)
}
```

```kotlin
val transportConfig = DittoTransportConfig()

transportConfig.connect.tcpServers.add("135.1.5.5:12345")
transportConfig.connect.tcpServers.add("185.1.5.5:12345")

ditto.transportConfig = transportConfig
ditto.startSync()
```

```javascript
import { TransportConfig } from '@dittolive/ditto'

const config = new TransportConfig()
config.connect.websocketURLs.push('wss://135.1.5.5:12345')
config.connect.websocketURLs.push('wss://185.1.5.5:12345')
ditto.setTransportConfig(config)
ditto.startSync()
```

```java
DittoTransportConfig config = new DittoTransportConfig();
DittoConnect connect = new DittoConnect();
connect.setTcpServers(Sets.newHashSet("135.1.5.5:12345", "185.1.5.5:12345"));
config.setConnect(connect);

try {
    ditto.startSync();
} catch(DittoError error) {
    // handle error
}
```

```csharp
DittoTransportConfig transportConfig = new DittoTransportConfig();
// Connect explicitly to a remote device on
transportConfig.Connect.TcpServers.Add("135.1.5.5:12345");
// you can add as many TcpServers as you would like.
transportConfig.Connect.TcpServers.Add("185.1.5.5:4567");
// set the transport config
Ditto.TransportConfig = transportConfig;
// now you can start ditto's sync
Ditto.StartSync();
```

```cpp
auto config = ditto::TransportConfig();
// Connect explicitly to remote devices
config.connect.tcp_servers.insert("135.1.5.5:12345");
config.connect.tcp_servers.insert("185.1.5.5:12345");

// set the transport config
ditto.set_transport_config(config);
// now you can start ditto's sync
ditto.start_sync();
```

```rust
let mut config = TransportConfig::new(); // empty

config
    .connect
    .tcp_servers
    .insert("135.1.5.5:12345".to_string()); // Custom TCP Listener
config
    .connect
    .tcp_servers
    .insert("185.1.5.5:12345".to_string()); // Custom TCP Listener
config
    .connect
    .websocket_urls
    .insert("wss://example.com".to_string()); // Custom WS endpoint

ditto.set_transport_config(config);
ditto.start_sync()?;
```
:::

## Initializing LAN-Based WebSocket Connections

If syncing over LAN, ensure WebSocket connections are discoverable across peers within your local network:&#x20;

:::CodeblockTabs
```swift
// not supported in Swift
```

```kotlin
val config = DittoTransportConfig()

config.connect.websocketUrls.add("ws://127.0.0.1")

ditto.transportConfig = config

ditto.startSync()
```

```javascript
import { TransportConfig } from '@dittolive/ditto'

const config = new TransportConfig()
config.connect.websocketURLs.push('ws://127.0.0.1')
ditto.setTransportConfig(config)
ditto.startSync()
```

```java
// not supported in Java
```

```csharp
DittoTransportConfig config = new DittoTransportConfig();

config.Connect.WebsocketUrls.Add("ws://127.0.0.1");

Ditto.TransportConfig = config;

Ditto.StartSync();
```

```cpp
// not supported in C++
```

```rust
//not supported in Rust
```
:::

# Listening for Connections

You can enable the Ditto instance to listen for incoming connections from other remotes Ditto peers on a specific port. You can think of this as setting up your Ditto as a "server" that can listen to connections from other peers.

In this example, we would like our Ditto instance to listen to *incoming* connections on port **4000** on **0.0.0.0**.

:::hint{type="info"}
To be safe, please do not use **localhost** when setting the IP interface. Use **"0.0.0.0"** instead.
:::

:::CodeblockTabs
```swift
var config = DittoTransportConfig()

// Listen for incoming connections on port 4000
config.listen.tcp.isEnabled = true
config.listen.tcp.interfaceIP = "0.0.0.0"
config.listen.tcp.port = 4000

ditto.transportConfig = config

do {
  try ditto.startSync()
} catch (let err) {
  print(err.localizedDescription)
}
```

```kotlin
val transportConfig = DittoTransportConfig()
transportConfig.connect.tcpServers.add("135.1.5.5:12345")
transportConfig.connect.tcpServers.add("185.1.5.5:12345")
ditto.transportConfig = transportConfig
ditto.startSync()
```

```javascript
import { TransportConfig } from '@dittolive/ditto'

const config = new TransportConfig()
config.listen.tcp.isEnabled = true
config.listen.tcp.interfaceIP = '0.0.0.0'
config.listen.tcp.port = 4000
ditto.setTransportConfig(config)
ditto.startSync()
```

```java
DittoTransportConfig config = new DittoTransportConfig();
config.enableAllPeerToPeer();

DittoListen listen = new DittoListen();
DittoTcpListenConfig tcpListenConfig = new DittoTcpListenConfig();
tcpListenConfig.setEnabled(true);
tcpListenConfig.setInterfaceIp("0.0.0.0");
tcpListenConfig.setPort(4000);
listen.setTcp(tcpListenConfig);
config.setListen(listen);

try {
    ditto.startSync();
} catch(DittoError error) {
    // handle error
}
```

```csharp
DittoTransportConfig transportConfig = new DittoTransportConfig();
transportConfig.Listen.Tcp = new DittoTcpListenConfig();
// By default Listen.Tcp.Enabled is false, be sure to set it to true.
transportConfig.Listen.Tcp.Enabled = true;
// if you want to listen on localhost, most likely you will use 0.0.0.0
// do not use "localhost" as a string
transportConfig.Listen.Tcp.InterfaceIp = "0.0.0.0";
// specify your port.
transportConfig.Listen.Tcp.Port = 4000;
Ditto.TransportConfig = transportConfig;

// now you can call `ditto.StartSync()`
Ditto.StartSync();
```

```cpp
auto config = ditto::TransportConfig();

config.listen.tcp.enabled = true;
config.listen.http.enabled = false;
config.listen.tcp.interface_ip = "0.0.0.0";
config.listen.tcp.port = 4000;

ditto.set_transport_config(config);
ditto.start_sync();
```

```rust
let mut config = TransportConfig::new(); // empty

config.listen.tcp.enabled = true;
config.listen.tcp.interface_ip = "0.0.0.0".to_string();
config.listen.tcp.port = 4000;
config.listen.http.enabled = false;

ditto.set_transport_config(config);
ditto.start_sync()?;
```
:::

Incoming connections from other Ditto peers will be able to connect only if the port is accessible. Depending on your deployment *be sure to check that external connections can reach the port* that you have specified in your configuration. You may need to set up port forwarding if external ports map differently to your host.

# Combining Multiple Transports

You can specify several modes of transport configuration within `DittoTransportConfig`. The following snippet shows you a ditto instance that can:

- Connect to local area network devices
- Listen for incoming remote connections
- Connect to remote devices with a known host and port.

:::CodeblockTabs
```swift
var config = DittoTransportConfig()
// 1. Enable All Peer to Peer Connections
config.enableAllPeerToPeer()

// 2. Listen for incoming connections on port 4000
config.listen.tcp.isEnabled = true
config.listen.tcp.interfaceIP = "0.0.0.0"
config.listen.tcp.port = 4000

// 3. Connect explicitly to remote devices
config.connect.tcpServers.insert("135.1.5.5:12345")
config.connect.tcpServers.insert("185.1.5.5:12345")

ditto.transportConfig = config

do {
  try ditto.startSync()
} catch (let err) {
  print(err.localizedDescription)
}
```

```kotlin
val transportConfig = DittoTransportConfig()
// 1. Enable All Peer to Peer Connections
transportConfig.enableAllPeerToPeer()
// 2. Listen for incoming connections on port 4000
transportConfig.listen.tcp.enabled = true
transportConfig.listen.http.enabled = false
transportConfig.listen.tcp.interfaceIp = "0.0.0.0"
transportConfig.listen.tcp.port = 4000
// 3. Connect explicitly to remote devices
transportConfig.connect.tcpServers.add("135.1.5.5:12345")
transportConfig.connect.tcpServers.add("185.1.5.5:12345")

ditto.transportConfig = transportConfig
ditto.startSync()
```

```javascript
import { TransportConfig } from '@dittolive/ditto'

const config = new TransportConfig()
if (isNode() && OS === 'darwin') {
// 1. Enable All Peer to Peer Connections (not in a browser environment)
config.setAllPeerToPeerEnabled(true)
// 2. Listen for incoming connections on port 4000
config.listen.tcp.isEnabled = true
config.listen.tcp.interfaceIP = '0.0.0.0'
config.listen.tcp.port = 4000

// 3. Connect explicitly to remote devices
ditto.setTransportConfig(config)
ditto.startSync()
```

```java
DittoTransportConfig config = new DittoTransportConfig();

// 1. Enable Peer to Peer Connections
config.enableAllPeerToPeer();

// 2. Listen for incoming connections on port 4000
DittoListen listen = new DittoListen();
DittoTcpListenConfig tcpListenConfig = new DittoTcpListenConfig();
tcpListenConfig.setEnabled(true);
tcpListenConfig.setInterfaceIp("0.0.0.0");
tcpListenConfig.setPort(4000);
listen.setTcp(tcpListenConfig);
config.setListen(listen);
// 3. Connect explicitly to remote devices
DittoConnect connect = new DittoConnect();
connect.setTcpServers(Sets.newHashSet("135.1.5.5:12345", "185.1.5.5:12345"));
config.setConnect(connect);

try {
    ditto.startSync();
} catch(DittoError error) {
    // handle error
}
```

```csharp
DittoTransportConfig transportConfig = new DittoTransportConfig();

// 1. Enable Local Area Network Connections
transportConfig.EnableAllPeerToPeer();

// 2. Listen for incoming connections on port 4000
transportConfig.Listen.Tcp.Enabled = true;
transportConfig.Listen.Tcp.InterfaceIp = "0.0.0.0";
transportConfig.Listen.Tcp.Port = 4000;

// 3. Connect explicitly to remote devices
transportConfig.Connect.TcpServers.Add("135.1.5.5:12345");
transportConfig.Connect.TcpServers.Add("185.1.5.5:12345");

ditto.TransportConfig = transportConfig;

ditto.StartSync();
```

```cpp
auto config = ditto::TransportConfig();
// 1. Enable All Peer to Peer Connections
config.enable_all_peer_to_peer();

// 2. Listen for incoming connections on port 4000
config.listen.tcp.enabled = true;
config.listen.http.enabled = false;
config.listen.tcp.interface_ip = "0.0.0.0";
config.listen.tcp.port = 4000;

// 3. Connect explicitly to remote devices
config.connect.tcp_servers.insert("135.1.5.5:12345");
config.connect.tcp_servers.insert("185.1.5.5:12345");

ditto.set_transport_config(config);
ditto.start_sync();
```

```rust
let mut config = TransportConfig::new(); // empty

// 1. Enable auto-discovery of peer to peer connections
config.enable_all_peer_to_peer(); // Auto-connect via lan and bluetooth

// 2. Configure TCP Listener
config.listen.tcp.enabled = true;
config.listen.tcp.interface_ip = "0.0.0.0".to_string();
config.listen.tcp.port = 4000;
config.listen.http.enabled = false;

// 3. Configure explicit, hard coded connections
config
    .connect
    .tcp_servers
    .insert("135.1.5.5:12345".to_string()); // Custom TCP Listener
config
    .connect
    .websocket_urls
    .insert("wss://example.com".to_string()); // Custom WS endpoint

ditto.set_transport_config(config);
ditto.start_sync()?;
```
:::

# Monitoring Conditions

If syncing over Bluetooth LE is a critical part of your application you may want to warn the user if they are missing the permission or if the hardware is disabled. Ditto will help you by reporting conditions via a delegate or callback object.

First, while configuring Ditto, assign a delegate or a callback to receive notifications.

:::CodeblockTabs
```swift
// Setting up inside a ViewController
let ditto = Ditto(identity: DittoIdentity.onlinePlayground(appID: "REPLACE_ME_WITH_YOUR_APP_ID", token: "REPLACE_ME_WITH_YOUR_PLAYGROUND_TOKEN"))
ditto.delegate = self
try! ditto.startSync()

// Now you can observe real time changes to the transport conditions:
extension ViewController: DittoDelegate {
   func transportConditionDidChange(transportID: Int64, condition: TransportCondition) {
       if condition == .BleDisabled {
           print("BLE disabled")
       } else if condition == .NoBleCentralPermission {
           print("Permission missing for BLE")
       } else if condition == .NoBlePeripheralPermission {
           print("Permission missing for BLE")
       }
   }
```

```kotlin
// ... Setting up inside an Activity
val androidDependencies = DefaultAndroidDittoDependencies(applicationContext)
val ditto = Ditto(androidDependencies, DittoIdentity.OnlinePlayground
(androidDependencies, appId = "REPLACE_WITH_APP_ID", token = "REPLACE_ME_WITH_YOUR_PLAYGROUND_TOKEN"))
ditto.callback = this
ditto.startSync()

// Now you can observe real time changes to the transport conditions:

class MainActivity : AppCompatActivity(), DittoCallback {

    override fun transportConditionDidChange(transportId: Long, condition: TransportCondition) {
        var toastText: String? = null
        if (condition == TransportCondition.TRANSPORT_CONDITION_BLE_DISABLED) {
            toastText = "BLE disabled"
        } else if (condition == TransportCondition.TRANSPORT_CONDITION_NO_BLE_CENTRAL_PERMISSION) {
            toastText = "Permission missing for BLE"
        } else if (condition == TransportCondition.TRANSPORT_CONDITION_NO_BLE_PERIPHERAL_PERMISSION) {
            toastText = "Permission missing for BLE"
        }
        toastText?.let {
            Handler(mainLooper).post {
                Toast.makeText(this, it, Toast.LENGTH_LONG).show()
            }
        }
    }
}
```

```javascript
const transportConditionsObserver = ditto.observeTransportConditions((condition, source) => {
  if (condition === 'BLEDisabled') {
    console.log('BLE disabled')
  } else if (condition === 'NoBLECentralPermission') {
    console.log('Permission missing for BLE')
  } else if (condition === 'NoBLEPeripheralPermission') {
    console.log('Permissions missing for BLE')
  }
})
```

```java
// Setting up inside an Activity
DefaultAndroidDittoDependencies androidDependencies = new DefaultAndroidDittoDependencies(getApplicationContext());
Ditto ditto = new Ditto(androidDependencies, new DittoIdentity.OnlinePlayground(androidDependenciesOne, "REPLACE_WITH_APP_ID"));
ditto.callback = this;
ditto.startSync();

// Now you can observe real time changes to the transport conditions:
public class MainActivity extends AppCompatActivity implements DittoCallback {
    @Override
    public void transportConditionDidChange(@NotNull DittoTransportCondition condition, @NotNull DittoConditionSource transportId) {
        String toastText = null;
        if (condition == DittoTransportCondition.BleDisabled) {
            toastText = "BLE disabled";
        } else if (condition == DittoTransportCondition.NoBleCentralPermission) {
            toastText = "Permission missing for BLE";
        } else if (condition == DittoTransportCondition.NoBlePeripheralPermission) {
            toastText = "Permission missing for BLE";
        }

        if (toastText != null) {
            String finalToastText = toastText;
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(MainActivity.this, finalToastText, Toast.LENGTH_LONG).show();
                }
            });
        }
    }
}
```

```csharp
// not supported in C#
```

```cpp
// not supported in C++
```

```rust
// not supported in Rust
```
:::

