# Brand the Connect UI

> Source: https://truto.one/docs/guides/link-sdk/branding/

Make the screen your customers connect their accounts on carry your name, your icon, and your terms. Branding is set per environment under **Settings → Branding** and applies to every connection that environment opens: the `authenticate` overlay or popup, the `connect-account` link, and the connect flow inside the [connections widget](/docs/guides/link-sdk/connections-widget).

:::skip-reading{skill="truto-link-sdk"}
:::

There is no styling option on `authenticate`. The Connect UI is a separate document, and branding belongs to a team admin, not to the page that opens it.

## 1. Set your brand

Open **Settings → Branding** (`app.truto.one/settings/branding`) with the environment selected in the dashboard. Saving changes requires the team admin role.

In the **Brand** card:

- **Brand name** — used in the Connect UI's headings and consent copy. Defaults to your team name when blank.
- **Icon logo** — click **Upload icon** and pick a square PNG, JPG, WEBP, or GIF up to 2 MB.

Click **Save changes**. To check the result against what's stored, fetch the environment's Connect UI config; its ID is the environment ID:

:::code-tabs

```bash label="cURL"
curl https://api.truto.one/link-ui/<environment_id> \
  -H "Authorization: Bearer <API token>"
```

:::

## 2. Set terms and consent

The **Terms and consent** card controls what your customers agree to before an account is connected:

- **Require a consent checkbox** — the user must tick a box before connecting.
- **Terms of service link** — the terms the consent line links to. Defaults to Truto's EULA when blank.
- **Custom consent text** — Markdown that replaces the default consent copy. A rendered preview appears under the editor.

The **White label** card's **White labelled** switch credits your brand instead of Truto in the consent line. It applies to every environment in the team, and Truto's name still appears on the intro screen and the unverified-team notice.

To reuse another environment's setup, pick it in **Copy from another environment** and click **Copy**. The form fills in; nothing changes until you save.

## 3. Add custom CSS

For what the fields can't express, the **Custom CSS** card takes a stylesheet. Turn on **Enable custom CSS**, write rules against the Connect UI's `data-truto-el` attributes, and save:

```css
/* Squarer cards, and your own colour on the primary action. */
[data-truto-el="card"] {
  border-radius: 4px;
}

[data-truto-el="submit"] {
  background-color: #1e5eff;
  border-radius: 6px;
}

[data-truto-el="submit"]:hover {
  background-color: #1a52e0;
}
```

These thirteen attributes are the only supported selectors:

| Selector | What it is |
| --- | --- |
| `[data-truto-el="root"]` | The outermost element, the backdrop behind the card |
| `[data-truto-el="card"]` | The card every screen renders inside |
| `[data-truto-el="content"]` | The scrolling area holding the current screen |
| `[data-truto-el="header"]` | A screen's top bar: its title and the back button |
| `[data-truto-el="catalog"]` | The integration picker's list |
| `[data-truto-el="integration"]` | One integration in the picker |
| `[data-truto-el="search"]` | The integration picker's search input |
| `[data-truto-el="form"]` | The fields on a screen: credentials and the setup form |
| `[data-truto-el="actions"]` | The button cluster at the bottom of a screen |
| `[data-truto-el="submit"]` | The primary action: Connect, Get Started, Continue |
| `[data-truto-el="status"]` | A warning, error, or success panel |
| `[data-truto-el="empty"]` | The zero-state when a search matches no integration |
| `[data-truto-el="footer"]` | The powered-by and terms strip beneath the card's content |

The rules:

- **Name an element outside pseudo-classes.** Each comma-separated selector must name one of the attributes above outside any functional pseudo-class. Write `[data-truto-el="card"], [data-truto-el="footer"]`, not `:is([data-truto-el="card"], [data-truto-el="footer"])`.
- **What else you can use.** The combinators `>`, `+`, `~` and descendant space; `:hover`, `:focus`, `:focus-visible`, `:active`, `:disabled`, `:first-child`, `:last-child`, `:not()`, `:is()`, `:where()`, `:has()`; `::before`, `::after`, `::placeholder`; `@media`, `@supports`, `@keyframes`; and CSS nesting, where `&` follows the same rules.
- **Dropped, not rejected.** Anything outside the contract is dropped and the rest of the stylesheet still applies. The editor shows what was kept and dropped, and why, as you type.
- **No positioning out of flow.** `position: fixed` and `position: sticky` are removed from any rule, because an out-of-flow rule can cover the Connect button. The rest of the rule is kept.
- **Refused on save.** `@import`, `@charset`, `</`, and control characters. The stylesheet is capped at 20,480 characters.
- **Not an API.** Truto's internal class names and `data-slot` attributes change without notice, and selectors that use them are dropped. Scripts and DOM injection are not supported.

Turning **Enable custom CSS** off and saving deletes the stylesheet stored for the environment.

## 4. Preview and troubleshoot

Click **Preview** to run the real Connect UI for the `truto-branding-preview` tenant beside the form, with your unsaved changes. Completing a connection there creates a test connection in the environment.

To see the Connect UI without your stylesheet, add `custom_css=off` to its URL:

```
https://app.truto.one/connect-account?link_token=<link token>&custom_css=off
```

If the problem disappears, your CSS is the cause.

## Connect UI CSS and widget CSS

The Connect UI and the [connections widget](/docs/guides/link-sdk/connections-widget) each have their own stylesheet:

| | Connect UI | Connections widget |
| --- | --- | --- |
| Set under | **Settings → Branding → Custom CSS** | **Settings → Connections widget → Custom CSS** |
| Styles | The connection flow: picker, credentials, consent, setup form | The embedded list of integrations and connections |
| Elements | The 13 above | 20 of its own, such as `toolbar`, `row`, `card-description` |

Saving one never changes the other, and a selector written for one matches nothing in the other. A `card` in the Connect UI is the flow's single card; in the widget it is one integration's card. When the widget opens a connect flow, that flow uses the Connect UI's stylesheet.

## Change branding through the API

The **Branding** page saves with `PATCH /link-ui/<environment_id>`, sending a `config` object. Truto merges the keys you send over the stored config at the top level, so a key you omit stays as it is, and sending `""` clears a text field:

```json
{
  "config": {
    "brand_name": "Acme",
    "require_tos_consent": true,
    "tos_link": "https://acme.example/terms",
    "eula_text": "",
    "custom_css": "[data-truto-el=\"card\"] { border-radius: 4px; }"
  }
}
```

`PATCH /link-ui/:id` accepts only a signed-in team admin. API tokens are refused with `403`, so branding can't be changed from a backend script; use **Settings → Branding**. `GET /link-ui/:id` works with an API token.

## Next

Embed the [connections widget](/docs/guides/link-sdk/connections-widget) to give customers a page for all their connections, or see the [Link SDK reference](/docs/sdks/link-sdk) for the options `authenticate` takes.
