6.1 KiB
date, title
| date | title |
|---|---|
| 2026-05-28 | Custom Brand Logo Url |
Problem
brandingUrl (the configured "Brand Website") is persisted and editable in branding
settings, but historically it was never consumed anywhere. It flowed into the database,
the settings form, and the admin read-only view, but never affected any rendered output.
We want brandingUrl to actually do something, with deliberately different behavior per
surface.
Relationship we're going for
brandingUrl is an email-only linking concept. It is intentionally not used on
in-app signing surfaces.
| Surface | Custom branding logo configured | brandingUrl behavior |
|---|---|---|
| Transactional emails (logo) | Logo shown | Logo links to brandingUrl when it is a safe http(s) URL; otherwise plain image |
| Transactional emails (footer) | n/a | brandingUrl rendered as a link in the footer when it is a safe http(s) URL |
| Signing pages (V1 + V2, normal + direct-template) | Logo shown | Ignored — logo is a plain image with no link |
| Signing pages (no custom logo) | Documenso fallback shown | Fallback keeps its internal / link |
| Embedded signing | Logo shown | Ignored (logo not linked) |
| Embedded authoring/editor | Logo shown | Ignored |
| Settings / admin branding previews | n/a | Unchanged (display only) |
Rationale:
- On signing pages the recipient is mid-task; sending them off to an external marketing site via the logo is undesirable, so the custom logo is a plain image there.
- In emails the logo and a footer link to the brand's own site are a normal, expected pattern and reinforce that the email is legitimately from that brand.
Decisions
Scope
- Use
brandingUrlonly in transactional email rendering:- The shared email logo component links the custom branding logo to
brandingUrl. - The shared email footer renders
brandingUrlas a link.
- The shared email logo component links the custom branding logo to
- On signing surfaces, render a configured custom branding logo as a plain image with no
link wrapper. Leave the Documenso fallback logo's internal
/link untouched. - Do not change embedded signing, embedded authoring/editor, or settings/admin previews.
- No Prisma schema or database migration.
brandingUrlalready exists and is editable.
URL safety
Rendering must be defensive because old/imported data can bypass the branding form's URL
validation. Only treat the stored value as a usable Brand Website when it parses as an
absolute http: or https: URL.
- Empty, missing, invalid, relative, or non-http(s) values are treated as "no Brand Website" and produce a plain logo / no footer link.
- Do not mutate stored settings or run a cleanup migration.
- Factored into a single shared helper so both email logo and footer apply identical rules:
packages/email/utils/branding-url.ts->getSafeBrandingUrl(value): string | null.
Email rendering
- New shared component
packages/email/template-components/template-branding-logo.tsx(TemplateBrandingLogo) renders either:- the custom branding logo, wrapped in a
Linkto the safebrandingUrlwithtarget="_blank"when one exists, or a plainImgwhen not; or - the Documenso fallback logo (
/static/logo.png) when custom branding is disabled or no logo is set.
- the custom branding logo, wrapped in a
- This component replaced the duplicated
brandingEnabled && brandingLogo ? <Img/> : <fallback/>ternary that was copy-pasted across all transactional email templates. packages/email/template-components/template-footer.tsxrendersbrandingUrlas a footer link (viagetSafeBrandingUrl) when branding is enabled and the URL is safe.
The branding context already exposes brandingUrl (packages/email/providers/branding.tsx),
populated by teamGlobalSettingsToBranding / organisationGlobalSettingsToBranding
(which spread ...settings), so no additional plumbing into the email branding context was
required.
Signing rendering
apps/remix/app/components/general/document-signing/document-signing-page-view-v1.tsx: custom logo renders as a bare<img>.brandingUrlis not read; the local branding type and loader payload no longer carry it.apps/remix/app/components/general/envelope-signing/envelope-signer-header.tsx(V2, shared by normal and direct-template signing): custom logo renders as a bare<img>; the Documenso fallback keeps its<Link to="/">.apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx: V1 loader branding payload no longer includesbrandingUrl.packages/lib/server-only/envelope/get-envelope-for-recipient-signing.tsandget-envelope-for-direct-template-signing.ts:brandingUrlremoved from the V2EnvelopeForSigningResponse.settingsschema/payload since it is not consumed there.
History
An earlier iteration of this plan wired brandingUrl into the in-app signing pages so a
custom logo linked to the Brand Website (external <a target="_blank">, internal /
fallback otherwise) and added brandingUrl to the V1/V2 signing payloads. That direction
was reversed: signing-page logos are now plain images and brandingUrl is email-only. The
signing payload additions were removed.
Test coverage
packages/app-tests/e2e/signing-branding.spec.ts:
- V1 normal
/sign/:token: custom logo is a plain image, not inside a link, and nobrandingUrllink is present. - V2 normal
/sign/:tokenand V2 direct-template: same plain-image assertions. - V2 with no custom logo: Documenso fallback still links to
/. - Embedded signing: no custom-logo Brand Website link is rendered.
Acceptance criteria
- A custom branding logo on any signing surface (V1, V2 normal, V2 direct-template, embedded)
renders as a plain image with no link, and
brandingUrlis never rendered as a link there. - Documenso fallback logos continue linking to
/. - In transactional emails, when a custom logo and a safe
brandingUrlare configured, the email logo links tobrandingUrl(new tab) and the footer shows the Brand Website link. - In transactional emails, when
brandingUrlis empty/invalid/relative/non-http(s), the logo is a plain image and no footer Brand Website link is shown. - URL safety is enforced through the single shared
getSafeBrandingUrlhelper. - Settings/admin branding previews are unchanged.
- No schema or migration changes.