Accrue's branding config drives visual customization of transactional emails and invoice PDFs. This guide covers the full schema and the logo strategy across HTTPS vs PDF rendering contexts.

Use the nested :branding keyword list (see below); it is the supported schema.

Quickstart

# config/config.exs
config :accrue, :branding,
  business_name: "Acme Corp",
  from_name: "Acme Billing",
  from_email: "billing@acme.example",
  support_email: "support@acme.example",
  company_address: "123 Main St, San Francisco, CA 94103",
  logo_url: "https://cdn.acme.example/logo.png",
  accent_color: "#1F6FEB",
  secondary_color: "#6B7280",
  font_stack: "-apple-system, BlinkMacSystemFont, sans-serif",
  list_unsubscribe_url: nil

All keys validate via nimble_options at boot — misconfig fails loud via Accrue.ConfigError.

Schema reference

KeyTypeDefaultRequiredPurpose
business_namestring"Accrue"noRendered as the sender name + used in {business} template interpolation
from_namestring"Accrue"noFrom: display name on Swoosh emails
from_emailstringyesFrom: address
support_emailstringyesRendered in Contact support at footer line
company_addressstringnilconditionalPhysical postal address shown in email footer. Required for EU/CA audiences per CAN-SPAM/CASL transactional exemptions — see guides/email.md
logo_urlstring (HTTPS)nilnoHTTPS-accessible logo. Used in email <img> src + PDF URL mode
accent_colorhex color (#RRGGBB)"#1F6FEB"noPrimary CTA button + link color
secondary_colorhex color (#RRGGBB)"#6B7280"noMuted text + borders
font_stackstring"-apple-system, BlinkMacSystemFont, sans-serif"noCSS font-family. Web-safe stack recommended
list_unsubscribe_urlstringnilnoOpt-in RFC 8058 List-Unsubscribe header URL. See guides/email.md "RFC 8058 opt-in"
theme:system | :light | :dark:systemnoCustomer-portal color-mode policy. See "Portal color-mode" below

Portal color-mode

The :theme option controls which color modes the mounted customer portal (accrue_portal) offers:

  • :system (default) — the portal offers both light and dark, driven by a three-way picker in the topbar (System / Light / Dark). "System" follows the visitor's OS preference; an explicit choice is remembered via the accrue_theme cookie. This is the standard, fully-themed experience.
  • :light / :dark — the portal is locked to that single mode. The mode is forced server-side (the accrue_theme cookie is ignored) and the picker is hidden — the affordance is simply absent when there is no choice to make.

Use :light or :dark when you only want to brand and ship a single color mode and would rather not maintain both. The option is library-only and requires no host code — set it under :branding and the portal honors it on the next request:

config :accrue,
  branding: [
    from_email: "billing@acme.test",
    support_email: "support@acme.test",
    theme: :light
  ]

Hex color validation

accent_color and secondary_color accept the following formats:

  • #RGB — 3-digit shorthand (#1F6)
  • #RRGGBB — 6-digit (#1F6FEB)
  • #RRGGBBAA — 8-digit with alpha (#1F6FEBFF)

Case-insensitive. Invalid values fail at boot with Accrue.ConfigError identifying the offending key.

Logo strategy

Emails and PDFs have different logo constraints, and the PDF posture depends on which renderer you chose:

FormatPreferred sourceWhy
HTML emaillogo_url (HTTPS)Email clients load the configured logo URL directly
PDF (Rendro)logo_url (HTTPS) or no logoThe current invoice renderer reads logo_url; if the render environment cannot reach that URL, verify the fallback text posture instead of assuming an embedded-logo config exists
PDF (ChromicPDF)logo_url (HTTPS)Chromium can fetch HTTPS assets at render time on the explicit compatibility path, but the host still owns network reachability and timeout behavior
PDF (restricted/offline)no logo or text fallbackAccrue does not currently expose a separate embedded-logo branding key for offline PDF rendering

Renderer-specific constraints

Rendro and ChromicPDF do not have the same asset and font behavior:

RendererAssetsFontsOperational note
RendroUses the configured logo_url when present, otherwise falls back to textValidate glyph coverage up front and verify logo reachability in the actual render environmentBest fit for deterministic invoice rendering without Chrome, but it does not add a separate offline logo embedding contract today
ChromicPDFUses the configured logo_url over HTTPS on the explicit compatibility pathBrowser-like CSS and webfont behavior exist, but remote fetch timing can still failOnly applies when the host explicitly opts into Accrue.InvoiceRenderer.ChromicPDF

If you care about air-gapped deploys, reproducible CI output, or environments where outbound fetches are restricted, verify the no-logo/text fallback output explicitly. Accrue does not currently expose a dedicated embedded-logo setting for PDF rendering.

Per-template override

Host apps can inject branding overrides on a per-type basis via the rung-3 override ladder (see guides/email.md). The default templates read branding via @context.branding — pass an overridden map via the mailer assigns pipeline.

Connect note

Stripe Connect platform branding always wins over per-connected-account overrides today. Accrue does not ship first-class per-account branding; use a rung-3 template override (see guides/email.md) that dispatches on the Connect account id at render time if you need it.

Admin chrome override

branding remains the customer-facing billing identity for emails, PDFs, and the mounted customer portal. If the mounted operator UI should keep a separate admin identity, set :admin_branding:

config :accrue,
  branding: [
    business_name: "Acme",
    from_email: "billing@acme.example",
    support_email: "support@acme.example",
    accent_color: "#26785F"
  ],
  admin_branding: [
    app_name: "Accrue Admin",
    accent_color: "#5D79F6"
  ]

When :admin_branding is unset, Accrue Admin derives its label, logo, and accent from branding for backwards compatibility.