This guide describes the unit preferences mechanism in Signal K Server.
Signal K Server allows you to define your preferred units for different categories of data (e.g., Speed, Depth, Temperature) centrally. These settings are applied across all compatible apps and dashboards.
You can configure your unit preferences in the Signal K Server Admin UI.
The simplest way to configure units is to select a Preset. A preset is a collection of unit preferences for all standard categories.
Available presets:
Preferences are stored per user. If you log in with your user account, your unit settings will follow you across different devices. If no user is logged in (or for anonymous users), the server's global default preset (configured by the administrator) is used.
Advanced users can upload Custom Presets to define specific combinations of units that aren't covered by the built-in options.
In addition to category-wide settings (e.g., "All speeds in Knots"), you can override units for specific data paths. For example, you might want Boat Speed in Knots but Wind Speed in Meters/Second.
An override is specific to a single path and is set under Data → Metadata. The override can specify either just the category for the path or directly the target unit. An override that names no target unit of its own follows the active preset's target unit choice for its category. An override that specifies the target unit takes precedence over the preset's setting for the category.
Unit categories are the mechanism that allows the server to apply unit preferences to a wide range of data paths without needing configuration for every single path.
speed, temperature, depth). This assignment is defined in the server's default configuration but can be customized.speed category expects m/s.speed category to kn (knots).This system means that if you set your speed preference to Knots, it applies to Boat Speeds, Wind Speeds and any other path assigned to the speed category.
The following categories are available by default:
navigation.speedOverGround, environment.wind.speedTrue.navigation.log, navigation.courseRhumbline.nextPoint.distance.environment.depth.belowTransducer, environment.depth.belowKeel.design.length.overall, design.airHeight.environment.outside.temperature, propulsion.*.temperature.environment.outside.pressure, propulsion.*.oilPressure.environment.wind.angleApparent, navigation.headingMagnetic.navigation.rateOfTurn.tanks.*.currentLevel.propulsion.*.fuel.rate.electrical.batteries.*.voltage.electrical.batteries.*.current.electrical.batteries.*.capacity.stateOfCharge.propulsion.*.revolutions.tanks.*.currentLevel, electrical.batteries.*.capacity.stateOfCharge.Additional categories include dateTime, epoch for time representations, and unitless/boolean for data that doesn't require conversion.
The Unit Preferences system simplifies client development by managing unit preferences centrally, on the server across all unit preferences aware client applications. As a developer, you don't need to maintain user preference settings in your application and can use the settings and conversion formulas provided by the server.
When you fetch metadata for a path (e.g., vessels.self.navigation.speedOverGround), the server checks the active unit preferences and includes a displayUnits object in the meta data.
Request the metadata for any path:
GET /signalk/v1/api/vessels/self/navigation/speedOverGround/meta
Response Example:
{
"units": "m/s",
"description": "Speed over ground",
"displayName": "SOG",
"displayUnits": {
"category": "speed",
"targetUnit": "kn",
"formula": "value * 1.94384",
"inverseFormula": "value / 1.94384",
"symbol": "kn",
"displayFormat": "0.0"
}
}
The displayUnits object provides everything you need to display the value:
value represents the input.A resolved response reads the same whether the target unit comes from a
path-specific override or from the applied preset. An editor has to tell the
two apart, so it asks for the answer with displayUnitsOverride=true:
GET /signalk/v1/api/vessels/self/navigation/speedOverGround/meta?displayUnitsOverride=true
The response then carries one more field in displayUnits:
targetUnit and displayFormat. Empty when the path follows the preset.The same parameter works on the WebSocket stream URL, next to sendMeta=all:
ws://localhost:3000/signalk/v1/stream?subscribe=none&sendMeta=all&displayUnitsOverride=true
Display code needs none of this, so the field is absent unless it is asked for.
A metadata PUT reads override even when the request did not ask for one, so
saving a resolved response back does not turn the preset's current settings into
a path-specific override. The metadata delta a PUT triggers carries the field
as well.
When subscribing to the WebSocket stream, add sendMeta=all to receive metadata once for each path (sent with the first delta for that path, and again only if it changes):
const ws = new WebSocket('ws://localhost:3000/signalk/v1/stream?subscribe=none')
ws.onopen = () => {
ws.send(
JSON.stringify({
context: 'vessels.self',
subscribe: [
{
path: 'navigation.speedOverGround',
policy: 'instant',
sendMeta: 'all'
}
]
})
)
}
Delta with Metadata:
{
"context": "vessels.urn:mrn:signalk:uuid:...",
"updates": [
{
"values": [
{
"path": "navigation.speedOverGround",
"value": 5.14,
"meta": {
"units": "m/s",
"description": "Speed over ground",
"displayUnits": {
"category": "speed",
"targetUnit": "kn",
"formula": "value * 1.94384",
"inverseFormula": "value / 1.94384",
"symbol": "kn",
"displayFormat": "0.0"
}
}
}
]
}
]
}
Using sendMeta=all eliminates the need for separate REST calls to fetch metadata.
sendMeta=all (recommended), or poll the REST API and fetch metadata separately.displayUnits - If present, the user has unit preferences configured.formula expression with the SI value as value.symbol and displayFormat.This ensures that if the user changes their preferences (e.g., from "Knots" to "m/s" or "km/h") on the server, your application automatically reflects those changes without any code updates.
The unit preferences system exposes the following REST API endpoints:
| Method | Endpoint | Description |
|---|---|---|
| GET | /signalk/v1/unitpreferences/config |
Get the current configuration |
| PUT | /signalk/v1/unitpreferences/config |
Update the configuration |
| GET | /signalk/v1/unitpreferences/categories |
Get all unit categories (merged standard + custom) |
| GET | /signalk/v1/unitpreferences/definitions |
Get all unit definitions (merged standard + custom) |
| GET | /signalk/v1/unitpreferences/custom-definitions |
Get custom unit definitions only |
| PUT | /signalk/v1/unitpreferences/custom-definitions |
Update custom unit definitions |
| GET | /signalk/v1/unitpreferences/custom-categories |
Get custom category mappings only |
| PUT | /signalk/v1/unitpreferences/custom-categories |
Update custom category mappings |
| GET | /signalk/v1/unitpreferences/presets |
List all available presets (built-in and custom) |
| GET | /signalk/v1/unitpreferences/presets/:name |
Get a specific preset by name |
| PUT | /signalk/v1/unitpreferences/presets/custom/:name |
Create or update a custom preset |
| DELETE | /signalk/v1/unitpreferences/presets/custom/:name |
Delete a custom preset |
| GET | /signalk/v1/unitpreferences/active |
Get the currently active preset |
| GET | /signalk/v1/unitpreferences/default-categories |
Get the default category mappings |