# Callbacks (/docs/webserial/callbacks)

> Handle commands and messages sent from the WebSerial terminal with the onMessage callback, as a String or as raw bytes.

Library: WebSerial

WebSerial provides a single callback, `onMessage()`. It notifies your firmware whenever a user sends a command or message from the terminal input bar. If no callback is registered, received messages are discarded.

## `onMessage()`

Register the callback in `setup()`. You can receive messages either as a `String` or as a byte buffer.

<Callout>
  Only one callback is active at a time. If you register both variants, the callback registered last takes precedence.
</Callout>

### Receive messages as a `String`

```cpp
WebSerial.onMessage([](const String& msg) {
  Serial.println(msg);
});
```

The `String` variant is invoked only for non-empty messages.

### Receive messages as raw bytes

```cpp
WebSerial.onMessage([](uint8_t *data, size_t len) {
  Serial.printf("Received %u bytes from WebSerial: ", len);
  Serial.write(data, len);
  Serial.println();
});
```

<TypeTable
  type={{
    data: { type: 'uint8_t*', description: 'Pointer to the received message. The data is not null-terminated.', required: true },
    len: { type: 'size_t', description: 'Length of the message in bytes.', required: true },
  }}
/>

## Callback types

| Type | Definition |
| --- | --- |
| `WSLMessageHandler` | `std::function<void(uint8_t *data, size_t len)>` |
| `WSLStringMessageHandler` | `std::function<void(const String& msg)>` |

## Example

The following callback parses simple commands and responds in the terminal:

```cpp
WebSerial.onMessage([](const String& msg) {
  if (msg.startsWith("uptime")) {
    WebSerial.printf("Uptime: %lums\n", millis());
  } else if (msg.startsWith("ip")) {
    WebSerial.println(WiFi.localIP());
  } else {
    WebSerial.println("Unknown command: " + msg);
  }
});
```

<Callout type="warn">
  The terminal appends a null byte (`\0`) to each message, and this byte is included in `len` and in the `String`. Compare commands with `startsWith()` or strip the trailing null byte before using `==`.
</Callout>

<Callout>
  In WebSerial Pro, the callback is not invoked while the input bar is disabled. See [Toggle Input](/docs/webserial/toggle-input).
</Callout>
