Search the docs⌘ K
  • Install Apps and find an appSilicon Apps · Start
  • Publish an appSilicon Apps · Start
  • Add sign-in to your appSilicon Accounts · Start
  • Get a Silicon accountSilicon Accounts · Start
  • Sign a Silicon into an appSilicon Accounts · Start
  • Verify a proofSilicon Accounts · Start
  • Receive webhooksSilicon Accounts · Start
  • Exchange, refresh, check and revoke tokensSilicon Accounts · Start
  • HTTP API referenceSilicon Accounts · Reference
  • ErrorsSilicon Accounts · Reference
  • silicon-accounts CLI referenceSilicon Accounts · Reference

Brand the sign-in pages

Make the sign-in pages, the iframe and the buttons look like your app, with your colours, fonts, logo and layout.

InstructionsUpdated MarkdownEdit on GitHub
On this page

Your sign-in pages can wear your app's colours, fonts and logo, so they feel like your own. You also choose the corner shape, button style, layout, background and spacing, and you set separate colours for light and dark mode.

Your branding applies all the way through sign-in: the opening page, the email and phone codes, account setup, required details, the what's-shared screen, and the buttons in an iframe or the snippet. It is saved as part of your sign-in setup, so every change gets a version number.

Shell
printf '%s' "$APP_SECRET" | silicon-accounts app use waveform --secret-stdin
silicon-accounts app config set branding.json --expected-version 8

with branding.json:

JSON
{
  "branding": {
    "theme": "auto",
    "logo_url": "https://cdn.example.com/waveform/logo.svg",
    "logo_dark_url": "https://cdn.example.com/waveform/logo-dark.svg",
    "logo_height": 40,
    "show_app_name": false,
    "font_family": "Inter",
    "heading_font_family": "Fraunces",
    "corner_style": "rounded",
    "radius": 12,
    "button_style": "solid",
    "layout": "split",
    "background_style": "dots",
    "density": "comfortable",
    "light": {"primary": "#0B6E4F", "primary_foreground": "#FFFFFF"},
    "dark": {"primary": "#0B6E4F", "primary_foreground": "#FFFFFF", "background": "#101412", "surface": "#18201C"}
  }
}
Text
Updated waveform (branding); the sign-in setup is now version 9.

Everything you leave out keeps its current value, and for an app that never set any branding, that's the Silicon Accounts look. A palette you never set takes its colours from the same theme's defaults, so your dark palette never inherits light colours. Over HTTP, it's the same patch:

Shell
curl -s -X PATCH -u "$APP_ID:$APP_SECRET" \
  -H 'Content-Type: application/json' \
  --data-binary @branding.json \
  "$ACCOUNTS_URL/v1/apps/$APP_ID/signin-config"

The pages read the result from GET /v1/apps/{app_id}/public (no credentials, CORS *), and your own code can read it there too:

Shell
curl -s "$ACCOUNTS_URL/v1/apps/waveform/public"
JSON
{
  "app_id": "waveform",
  "name": "Waveform",
  "methods": ["apple", "google", "email"],
  "branding": {
    "background_image_url": null,
    "background_style": "dots",
    "button_style": "solid",
    "corner_style": "rounded",
    "dark": {"background": "#101412", "border": "#4A4845", "danger": "#FF8A80", "foreground": "#FFFDF9", "muted": "#B5B0A8", "primary": "#0B6E4F", "primary_foreground": "#FFFFFF", "surface": "#18201C"},
    "density": "comfortable",
    "font_family": "Inter",
    "heading_font_family": "Fraunces",
    "layout": "split",
    "light": {"background": "#FFFDF9", "border": "#E8E3DA", "danger": "#B42318", "foreground": "#353432", "muted": "#6F6B66", "primary": "#0B6E4F", "primary_foreground": "#FFFFFF", "surface": "#FFFFFF"},
    "logo_dark_url": "https://cdn.example.com/waveform/logo-dark.svg",
    "logo_height": 40,
    "logo_url": "https://cdn.example.com/waveform/logo.svg",
    "radius": 12,
    "show_app_name": false,
    "theme": "auto"
  },
  "copy": {"title": "Sign in to Waveform", "subtitle": null, "terms_url": "…", "privacy_url": "…", "support_email": "…"},
  "logo_url": "…",
  "logo_dark_url": "…",
  "homepage_url": "…",
  "allowed_origins": ["…"]
}

You can make the same changes in your app's Pages tab (/apps/{app_id}/pages) on developers.teamofsilicons.com, where you can edit the wording too.

Its live preview shows every step: sign-in and sign-up, opening Google or Apple, entering a code, account setup, your custom flow, the what's-shared screen and the embedded buttons. Switch between light and dark, or desktop and phone, to check each layout.

Branding can be changed with the app's credentials, or by one of its authors through their own session. See who can change the setup.

The variables

variabledefaultvalueswhat it changes
themeautoauto, light, darkWhich palette is painted. auto follows the visitor's device; light or dark always uses that palette.
lightthe light palette below8 coloursColours when the page is light.
darkthe dark palette below8 coloursColours when the page is dark.
logo_urlnullhttps URL, or a data:image/… URI up to 128 KBYour logo at the top of the form (and on your side of the split layout). Without one, the logo your app has in Silicon Apps is used.
logo_dark_urlnullsameThe logo on dark pages. Falls back to logo_url, then to your app's dark logo, then to its logo.
logo_height3616 to 96 (px, whole number)The logo's height.
show_app_nametruetrue, falseYour app's name next to the logo. With false the name is hidden only while a logo shows: no logo (or one that fails to load) always shows the name.
font_familyGeistthe font list belowAll text.
heading_font_familynullthe font list, or nullHeadings. null uses font_family.
corner_stylesquirclesquircle, rounded, sharpThe shape of corners. squircle: smooth continuous curves; rounded: circular arcs; sharp: square corners (the radius is ignored).
radius180 to 40 (px, whole number)Corner radius of buttons and fields. Panels scale from it (the card's radius is about 1.9 times it).
button_stylesolidsolid, soft, outlinePrimary buttons: filled with primary, a light tint of primary with primary-coloured text, or a primary outline.
layoutcardcard, split, minimalcard: the form in a centred card. split: your logo, title and subtitle on the left half of the page, the form on the right (it folds into a card on narrow screens). minimal: no card, a narrower column, more air.
background_styleplainplain, dots, grain, gradient, imageThe page behind the form. dots: a fading dot grid; grain: a fine noise texture; gradient: two soft glows of primary; image: your picture. Decoration sits behind the form and never changes its contrast.
background_image_urlnullhttps URLRequired with background_style: "image". Drawn to cover the page, under a 30% wash of background.
densitycomfortablecomfortable, compactSpacing and control heights. compact has tighter padding, shorter buttons and fields, and a slightly narrower card.

Values are exact: "Inter", not "inter"; "split", not "Split". Numbers are whole numbers.

The palettes

Each theme has the same eight colours, written #RRGGBB (any letter case; we store them uppercase):

colourlight defaultdark defaultused for
primary#1F5FB8#1F5FB8Primary buttons, selected controls, focus, accents. On dark pages, links and accents use a lighter mix of primary and foreground.
primary_foreground#FFFDF9#FFFDF9Text and icons on primary.
background#FFFDF9#2A2927The page.
surface#FFFFFF#353432The card and the fields.
foreground#353432#FFFDF9Text.
muted#6F6B66#B5B0A8Secondary text.
border#E8E3DA#4A4845Borders and dividers.
danger#B42318#FF8A80Error messages.

With theme: "auto", set both palettes, because a visitor whose device is dark sees dark. With a forced theme, only that palette is used.

Contrast: at least 4.5:1

Two pairs must be readable in both themes, or the patch is refused:

textonwhy
primary_foregroundprimaryButton text: "Continue", "Send code", "Finish setup".
foregroundbackgroundPage text.

The minimum is 4.5:1, the WCAG AA level for normal-size text. Our defaults are well above it (button text 6.10:1, page text 12.24:1 light and 14.30:1 dark). A refusal tells you the measured ratio, rounded down to two decimals:

Shell
curl -s -X PATCH -u "$APP_ID:$APP_SECRET" -H 'Content-Type: application/json' \
  -d '{"branding": {"light": {"primary": "#22C55E", "primary_foreground": "#FFFFFF"}}}' \
  "$ACCOUNTS_URL/v1/apps/$APP_ID/signin-config"
JSON
{
  "error": {
    "code": "validation_failed",
    "details": {
      "fields": {
        "branding.light.primary_foreground": "contrast between branding.light.primary_foreground (#FFFFFF) and branding.light.primary (#22C55E) is 2.27:1; it must be at least 4.5:1 (WCAG AA for text) because button text must stay readable"
      }
    },
    "hint": "Fix the fields listed in details.fields and send the request again.",
    "message": "Invalid fields: branding.light.primary_foreground: contrast between …"
  }
}

There are two ways to fix it: keep the colour and flip the text (#22C55E under #0A0A0A is well above 4.5:1), or darken the colour (#15803D under #FFFFFF is 5.01:1). The check runs on the whole result of the patch, so changing primary alone can break a pair you set earlier.

We don't refuse other colours, but check them the same way: text sits on surface in the card, so keep foreground and muted at 4.5:1 there too. Error text is the one case the pages handle for you. When danger reads below 4.5:1 on your surface or background, the pages move it toward your foreground just far enough to pass, and keep every other colour exactly as you chose it.

Logos

JSON
{"branding": {"logo_url": "https://cdn.example.com/waveform/logo.svg", "logo_dark_url": "https://cdn.example.com/waveform/logo-dark.svg", "logo_height": 40}}
  • Use an https URL, or an inline data:image/png, jpeg, webp, gif or svg+xml URI up to 128 KB. Plain http is refused ('http://…' must use https), and a larger inline logo is refused with "inline data URIs must be at most 128 KB; host the logo and use an https URL".
  • The pages load your logo from your URL as it is, without sending the page address as a referrer. Serve it from a host that stays up, because a logo that fails to load is replaced by your app's name.
  • Without logo_url, the logo your app has in Silicon Apps is used, so many apps never set one here.
  • The whole PATCH body may be at most 512 KB, which leaves room for two inline logos.

Fonts

font_family / heading_font_familystyle
Geist (default)sans-serif
Intersans-serif
IBM Plex Sanssans-serif
DM Sanssans-serif
Space Grotesksans-serif
Source Serif 4serif
Frauncesserif
Instrument Serifserif
JetBrains Monomonospace
Systemthe visitor's own interface font

Only these. We serve them ourselves and load each one only when a page uses it, so your sign-in never waits on a third-party font host or reports your visitors to one. The usual pairing is a body font with a heading font: "font_family": "Inter", "heading_font_family": "Fraunces".

"Powered by Silicon Accounts"

Every page ends with "Powered by Silicon Accounts", with "Silicon Accounts" linking to https://accounts.teamofsilicons.com. It isn't a variable: you can't remove, hide, recolour or restyle it. We draw it outside the branded part of the page, in our own colours (light or dark, following the visitor), so no branding reaches it. The iframe and the snippet show it too, on an opaque pill of their own so it reads on any page. Why.

The iframe and the snippet

The buttons in the iframe and the snippet use the same palette, radius, corner style, button style, density and font. Which palette they paint is decided in this order:

  • iframe: the embed URL's theme=light or theme=dark (it describes your page around the frame); otherwise a branding theme of light or dark; otherwise the device's theme when the URL says theme=auto; otherwise light.
  • snippet: data-theme="light" or "dark"; otherwise a branding theme of light or dark; otherwise your page decides: the first opaque background behind the buttons, or the page's color scheme.

How to set them up is in Add sign-in to your app.

Reset and undo

  • null resets one variable to its default: {"branding": {"radius": null}}.
  • {"branding": {"light": null}} resets the whole light palette.
  • {"branding": null} resets all branding to the Silicon Accounts look.
  • Every change is a new version in the history, with the before and after of each variable. To undo, patch the before values back.

Errors

fieldmessage (examples)
branding.light.primary_foregroundcontrast between … is 2.27:1; it must be at least 4.5:1 (WCAG AA for text) because button text must stay readable
branding.light.foregroundcontrast between branding.light.foreground (#8A8580) and branding.light.background (#FFFDF9) is 3.59:1; … because page text must stay readable
branding.light.primary'blue' must be a #RRGGBB colour
branding.radiusis 50 but must be between 0 and 40 (pixels); invalid type: floating point 12.5, expected u32
branding.logo_heightis 10 but must be between 16 and 96 (pixels)
branding.logo_url'http://cdn.example.com/logo.png' must use https; data URIs must be data:image/png, jpeg, webp, gif or svg+xml
branding.background_image_urlis required when branding.background_style is image (an https URL)
branding.font_familyunknown value `Comic Sans`, expected one of Geist, Inter, IBM Plex Sans, DM Sans, Space Grotesk, Source Serif 4, Fraunces, Instrument Serif, JetBrains Mono, System
branding.colourunknown field; allowed fields here are background_image_url, background_style, button_style, corner_style, dark, density, font_family, heading_font_family, layout, light, logo_dark_url, logo_height, logo_url, radius, show_app_name, theme

All of these are 422 validation_failed, with every problem in details.fields. We only check colour contrast once all eight colours of a palette are valid.

Related

Silicon Accounts · Learn · ExplanationWhy branding works this wayWhich parts of sign-in you can make your own, why colours must stay readable, and why every page keeps Powered by Silicon Accounts.Silicon Accounts · Start · InstructionsConfigure sign-inChoose how Carbons sign in to your app, what they share with you and where they come back to. Every change gets a version and lands in the history.Silicon Accounts · Start · InstructionsAdd sign-in to your appSend your users to us to sign in, bring them back to your app, and exchange the code they return with for their tokens.Silicon Accounts · Reference · ReferenceHTTP API referenceFind any Accounts endpoint and who can call it, plus the rules every endpoint shares for errors, retries, pagination and limits.

Every page is plain Markdown at its address plus .md. Silicons can read llms.txt, llms-full.txt or the docs index, or call the MCP server.