[API reference](https://evolu.dev/docs/api-reference) › [@evolu/common](https://evolu.dev/docs/api-reference/common) › [local‑first/Owner](https://evolu.dev/docs/api-reference/common/local-first/Owner) › RelayUrl

```ts
const RelayUrl: brand(
  "RelayUrl",
  WebSocketUrl,
  (value: string) =>
    // Only a query adds "?" to a serialized URL without a fragment.
    value.includes("?")
      ? err<RelayUrlError>({ type: "RelayUrl", value })
      : ok(),
  (error) =>
    `The value ${JSON.stringify(error.value)} is not a relay URL, which has no query.`,
);
```

Defined in: [packages/common/src/local-first/Owner.ts:583](https://github.com/evoluhq/evolu/blob/aa223771feea747ffb1b0f5f3271574455633e37/packages/common/src/local-first/Owner.ts#L583)

[WebSocketUrl](https://evolu.dev/docs/api-reference/common/WebSocket/variables/WebSocketUrl) of a relay, which has no query, such as
`wss://free.evoluhq.com/`.

[createOwnerWebSocketTransport](https://evolu.dev/docs/api-reference/common/local-first/Owner/functions/createOwnerWebSocketTransport) adds the [OwnerId](https://evolu.dev/docs/api-reference/common/local-first/Owner/variables/OwnerId) as the query. A
relay that admits a connection by a credential beyond the OwnerId, such as a
token that a reverse proxy checks, takes it in the path. Like WebSocketUrl,
RelayUrl does not normalize; use [RelayUrlFromString](https://evolu.dev/docs/api-reference/common/local-first/Owner/variables/RelayUrlFromString) to convert other
spellings, such as user input.

### Example

```ts
import { assertErr, assertOk, RelayUrl } from "@evolu/common";

assertOk(
  RelayUrl.fromUnknown("wss://free.evoluhq.com/"),
  "wss://free.evoluhq.com/",
);

assertErr(RelayUrl.fromUnknown("wss://free.evoluhq.com/?token=1"), {
  type: "RelayUrl",
  value: "wss://free.evoluhq.com/?token=1",
});
```