HAP - Customizing the Appearance
How to brand the screens the platform renders on your behalf — the sign-in pages, the signed-out page, the invitation welcome page, and the tenant Admin Console — so they look like your product: your colours, your font, your logo, your name.
Status: available now. Appearance customization shipped in
specs/015-ui-branding-customization. It is a per-tenant setting, fully optional, and backward compatible: a tenant that configures nothing keeps the default look, and a tenant that previously set only an accent colour and logo is unaffected.
Who this is for: tenant administrators. You can configure appearance two ways — through the Admin Console (self-service, no code) or by asking a platform operator to set it via the admin API. Both write the same configuration. End users never see these controls.
What you can customize
One appearance configuration drives every platform-rendered screen at once, so they always look consistent. You can set any subset; anything you leave blank uses a sensible default.
| Setting | What it controls | Format | Default |
|---|---|---|---|
| Product / display name | The name shown in page titles and headings ("Sign in to Acme"). | Plain text, ≤ 80 characters | Your tenant name |
| Accent colour | Buttons and links — your primary brand colour. | Hex, e.g. #2563eb or #fff | #2563eb (blue) |
| Background colour | The page background. | Hex | #ffffff (white) |
| Text colour | Body text. | Hex | #111827 (near-black) |
| Error colour | Error and warning messages. | Hex | #b91c1c (red) |
| Font | The typeface used across the screens. | A name from the supported list (below) | System font |
| Logo | An image shown above the heading. | Absolute https:// URL to an image | None |
| Favicon | The icon in the browser tab. | Absolute https:// URL to an icon | None |
Supported fonts
Pick a font by name from this list. The platform loads it for you from its web-font provider — you don't supply a font file or URL.
System (the default — uses the visitor's device font, no external load), Inter, Roboto,
Open Sans, Lato, Montserrat, Source Serif 4, Merriweather, JetBrains Mono.
If a chosen web font can't load in a visitor's browser, the screen falls back to the system font automatically — text is never invisible.
Which screens are affected
Your appearance configuration applies to all of these, consistently:
| Screen | Where the user sees it |
|---|---|
| Hosted Login (email + code steps) | When signing in to any app that delegates login to the platform. |
| Signed-out page | After logging out (when no return URL is configured). |
| Invitation welcome page | When a newly invited user opens their invitation link. |
| Tenant Admin Console | When a tenant administrator manages users, groups, and appearance. |
Screens rendered by your own applications are not affected — those are styled by the app itself.
Option A — Self-service in the Admin Console (no code)
This is the easiest path and requires no operator involvement.
- Sign in to your tenant and open the Admin Console at
https://<auth-host>/t/<your-tenant>/hosted/admin. (You must be a tenant administrator. The Admin Console is only available when Hosted Login is enabled for your tenant.) - Under Appearance, click "Customize the look of your sign-in & account screens →".
- Fill in any of the fields. Leave a field blank to use the platform default.
- Click Save appearance. You'll see a confirmation, and the change takes effect immediately — open your sign-in page in a new tab to see it.
If a colour combination is hard to read (low contrast), you'll see a warning but the value is still saved — see Readable colours below.
Option B — Set it via the admin API (platform operator)
A platform operator can configure appearance with a single PATCH to the tenant, for example as
part of provisioning. All keys are optional; send only what you want to set.
curl -X PATCH "$HAP_BASE/v1/tenants/$TENANT_ID" \
-H "X-Admin-Key: $ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"branding": {
"product_name": "Acme Cloud",
"accent_color": "#1d4ed8",
"background_color": "#ffffff",
"text_color": "#111827",
"font_family": "Inter",
"logo_url": "https://cdn.acme.com/logo.svg",
"favicon_url": "https://cdn.acme.com/favicon.ico"
}
}'The response includes a branding_warnings array — empty when all is well, or containing
non-blocking readability warnings (e.g. low contrast).
- Update part of the config: send only the keys you want to change… (note: the API replaces
the stored
brandingobject with what you send, so include every key you want to keep). - Clear all branding (back to defaults): send
"branding": {}.
Verifying the result
- Sign-in screen: open
https://<auth-host>/t/<your-tenant>/hosted/login(you can reach it from any app that uses Hosted Login). Confirm your colours, font, logo, favicon (browser tab), and product name appear. - Admin Console: the console itself reflects your branding, so you'll see changes there too.
- Invitation page: send yourself a test invitation and open the link.
No deploy or restart is needed — changes apply to newly rendered pages right away.
Readable colours (contrast)
The platform checks the contrast between your text and background, and between white button text and your accent colour. If either is below a comfortable reading threshold, you'll get a non-blocking warning — the values are still saved, but visitors may find the screen hard to read.
Tips:
- Pair dark text on a light background (or vice-versa).
- Choose an accent colour dark enough that white button text stands out — light pastels often fail this. (A medium-to-dark blue, green, or purple usually passes; a pale sky-blue often won't.)
- When in doubt, keep the default background/text and change only the accent.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| "must be an absolute https:// URL" | Logo/favicon URL isn't https://, is relative, or is a data: URI. | Host the asset at a public https:// URL and use that. |
| "must be a hex colour" | A colour wasn't a hex value like #2563eb or #fff. | Use 3- or 6-digit hex with a leading #. |
| "must be one of the supported fonts" | The font name isn't in the supported list. | Pick a name from Supported fonts (names are case-sensitive). |
| Logo doesn't appear | The image URL is wrong/unreachable, or not actually an image. | Open the URL directly in a browser to confirm it loads. |
| Font looks like the system default | The web font couldn't load for that visitor. | This is the safe fallback; usually transient. Confirm the font name is correct. |
| A warning about contrast | Your colours may be hard to read. | See Readable colours. The value is still saved. |
What's not covered (this version)
- Custom CSS / HTML / JavaScript. For safety, you customize via the curated settings above, not by injecting arbitrary styles or markup.
- Uploading font files or custom font URLs. Fonts are chosen by name from the supported list.
- Per-application or per-screen themes. Branding is configured once per tenant and applied everywhere consistently.
- Light/dark mode switching or end-user appearance preferences.
- Hosting your logo/favicon. Host the images yourself and reference them by
https://URL.
Related: Hosted Login Guidelines · Getting Started with HAP