White-Label¶
White-label on Revel means an organization can present its attendee journey under its own look: its own brand colors on every page, and optionally its own domain such as events.example.org, instead of the Revel look and the Revel address. It is still one platform. There is one backend, one database and one set of Revel accounts. A custom domain is another front door to the same organization, not a separate instance.
This section has three guides, one per audience, plus an architecture page for people changing the code.
| You are... | Read |
|---|---|
| An organizer who wants brand colors or a custom domain | Organizer guide |
| Running a Revel instance (hosted or self-hosted) and enabling domains for organizations | Platform operator guide |
| Working on the backend | White-label architecture |
The frontend half (how a host becomes a tenant, which routes exist on a tenant domain, SEO, embeds) lives in the frontend repository: Tenant mode, Embeds and the deployment runbook. This guide links to those pages instead of repeating them.
What an organization gets¶
There are two layers, with different gates.
| Brand colors | Custom domain | |
|---|---|---|
| What it is | A primary color and an optional accent that restyle the organization's pages, embeds, wallet passes and ticket PDFs | The whole attendee journey (organization page, events, applications, checkout) served from the organization's own hostname |
| Who can use it | Every organization, free | Organizations a platform admin has enabled (a Django admin flag) |
| Who sets it up | Organizers with the "edit organization" permission | The organization owner, once the platform has enabled it |
| Needs DNS work | No | Yes, a CNAME and an ownership TXT record at the organization's DNS provider |
On a custom domain the visitor sees the organization's name and logo in the header, the organization's colors across the whole site (login, account and legal pages included), only the organization's own events, and an organization-scoped sitemap, favicon and page titles. Platform discovery and marketing pages do not appear there.
Organization emails that carry the organization's identity show its logo, and links in attendee emails (tickets, invitations, reminders, payment confirmations) point at the custom domain once it is active.
The deliberate limits¶
White-label on Revel is not "run your own ticketing site with the platform hidden". Some things stay Revel's on purpose, and each has a reason.
Accounts are shared Revel accounts. An attendee who signs up on events.example.org creates a Revel account, the same account they would get anywhere else on Revel. Revel stays the data controller for accounts, which is why the footer links to Revel's privacy policy and terms. Sessions are host-only, so each domain asks for its own login, and a session ends when its domain stops serving. Single sign-on buttons are hidden on custom domains, because the OIDC callback belongs to the platform.
Login happens on the custom domain. An attendee types their password into a page served under a hostname whose DNS the organization controls. Revel keeps every account-level token (email verification, password reset, deletion, unsubscribe) off tenant links, but an owner who repoints their DNS could still serve a look-alike login page. This is inherent to a login per domain and is why custom domains are enabled by a platform admin only, can be switched off at once, and raise alerts when a live domain develops a problem. A login made on a custom domain is also bound to that host: if the domain is removed, fails (including when Cloudflare reports it moved) or is switched off, those sessions stop working. See the password trade-off.
The footer says "Powered by Revel · Privacy · Terms". Every tenant page keeps this small footer, and organizers cannot turn it off.
Email comes through Revel. Mail an organization sends goes out as "<Org> via Revel" <[email protected]> (the domain is the operator's ORG_EMAIL_DOMAIN), with Reply-To set to the organization's verified contact email. On a custom domain, ticket and payment emails to attendees use the same organization sender. Sending from the organization's own domain is not supported. Account emails (verification, password reset, account deletion) always come from Revel and always link to Revel's own site, never to the custom domain. The organizer guide explains why.
Checkout is Stripe hosted Checkout. Payments go through the organization's own Stripe account, so the Stripe page already shows that account's branding. Revel does not embed the payment form in the page. The return trip from Stripe starts on the Revel address and ends back on the organization's domain.
Organizations stay listed in Revel discovery. An organization with a custom domain still appears in Revel's own listings and search, and its events still show up in discovery. Opening one leads to the organization's domain. An organization that wants to be reachable only through its own domain sets its visibility to Unlisted: it then disappears from discovery listings but stays reachable by direct link, including through its custom domain.
How it fits together¶
flowchart LR
V([Visitor]) -->|events.example.org| CF["Cloudflare for SaaS<br/>custom hostname + certificate"]
CF --> CD["Caddy<br/>catch-all block"]
CD -->|"X-Forwarded-Host / -Proto"| FE["Frontend<br/>tenant mode"]
FE -->|"GET /api/organizations/by-domain/{host}"| API["Revel API"]
API --> DB[("Organization.custom_domain<br/>+ branding")]
API -.->|"every 15 min:<br/>events.sync_custom_domains"| CF
ORG([Organizer]) -->|"request domain, set colors"| API - The organizer requests a hostname in the admin area. The API registers it with Cloudflare and returns the DNS records to create.
- The organizer creates the records (a CNAME and an ownership TXT). Cloudflare validates the hostname and issues a certificate.
- A background task (or the organizer's "Check now") notices that Cloudflare is ready and that the ownership TXT record is published in public DNS, and marks the domain active. Only then does the hostname resolve to the organization.
- A visitor opens the hostname. Cloudflare terminates TLS and forwards to Caddy, which forwards to the frontend with the original host. The frontend asks the API which organization owns that host, then renders that organization's site with its colors.
Without Cloudflare (self-hosting), steps 1 to 3 shrink to "a platform admin activates the domain in the Django admin", and TLS is the operator's job. See running without Cloudflare.
Where to go next¶
- Organizers: colors, custom domain and what attendees see
- Operators: enabling domains, Cloudflare, environment variables, go-live checklist
- Developers: architecture