Founder & Lead Engineer, RAITHub
A white-label SaaS platform is one multi-tenant codebase that each customer or reseller runs under their own brand: their logo and colours, their domain with automatic TLS, email from their address, and data the database keeps apart. Domains are inexpensive to serve: Cloudflare for SaaS includes 100 custom hostnames, then charges $0.10 each (Cloudflare). Isolation is the part that is expensive to get wrong.
If you would rather have it built for you, see how RAITHub would build this below.
This guide covers the six layers that make a product white-label: theming, custom domains, branded email, tenant isolation, a reseller and partner hierarchy, and per-tenant feature flags. The foundations under them, tenancy models, RBAC, billing and audit, are in the multi-tenant SaaS guide, and a worked vertical example is the white-label property portal for agencies.
What is a white-label SaaS platform, and what does "white-label" have to cover?
Your software, sold under someone else's name. The test is simple: could an end user of your customer's brand ever see your name, your domain or another customer's data? Every layer below exists to keep the answer "no".
| Layer | What the tenant expects | Where it usually leaks |
|---|---|---|
| Theming | Their logo, colours, fonts and favicon everywhere | Login page, error pages, PDF invoices, browser tab title |
| Domain | app.theirbrand.com or theirbrand.com, over HTTPS | Redirects to your domain after login or password reset |
| Mail from their address, in their design | "via yourplatform.com" in Gmail, your logo in the footer | |
| Isolation | No other tenant can see or affect their data | A missed tenant filter, a shared cache key, a cookie on a shared domain |
| Hierarchy | Resellers manage their own customers, and only theirs | A reseller admin who can reach a sibling reseller's tenant |
| Features | Their plan, their switches, their rollout | One global flag that turns a feature on for everyone |
Buy, build or hire?
| Route | Examples | Choose this when | The catch |
|---|---|---|---|
| Off-the-shelf white-label product | HighLevel's Agency Pro plan at $497 a month includes "SaaS Mode" for reselling subscriptions; its white-label mobile app is a separate $497-a-month add-on (HighLevel pricing). Vertical products exist for LMS, property and booking | A vendor already does what your customers need and you are selling the brand, service and relationship | You resell their roadmap, their limits and their outages; the product is not yours to differentiate |
| Template or starter kit | Vercel's guide to a multi-tenant Next.js app with custom domains, built on further by your own developers | You have developers, a simple product and a few dozen tenants to start | Starters solve routing and domains; isolation, resellers, email and billing are still yours to build and test |
| Custom multi-tenant build | Your own codebase on Postgres with row-level security, a domain API and per-tenant configuration | White-label is the business model: resellers, many brands, contractual separation, your own pricing | Real engineering and ongoing ownership; tenant isolation has to be tested on every build |
How does per-tenant theming work without a separate build per customer?
Store each tenant's brand as validated design tokens, not raw CSS, and render them as CSS custom properties on every request. One build serves every brand.
- Tokens, not stylesheets. Primary and accent colours as validated hex values, a font from an allowed list, a corner radius, a logo and favicon. Free-form CSS from tenants is a cross-site scripting and support risk.
- Check contrast on save. A tenant's brand colour on white text can fail accessibility. Reject or adjust colours below a contrast ratio of 4.5:1 for body text, the WCAG AA level (W3C).
- Treat uploaded SVG logos as code. SVG can carry scripts. Sanitize or rasterize them, and serve them from a separate asset domain.
- Theme the forgotten surfaces. Error and 404 pages, the login and reset screens, PDFs, the browser title and the favicon. These are where white-label usually fails a customer demo.
- Cache per host. If a page is cached by path alone, tenant A's logo can be served to tenant B. Make the host, or the tenant ID, part of every cache key.
How do custom domains and TLS work for each tenant?
Offer two levels: a free subdomain on your domain from day one, and a "bring your own domain" option that your code provisions, verifies and certifies through a platform API.
Subdomains. On Vercel, a wildcard domain such as *.yourplatform.com gets one wildcard certificate that covers every tenant subdomain at that level. Vercel needs DNS challenge access to issue and renew it, so the domain uses Vercel's nameservers or delegates the challenge (Vercel multi-tenant domains).
Custom domains. Vercel's docs describe three steps for a tenant's own domain: add it to your project through the SDK, verify ownership, and let Vercel issue a certificate automatically; each custom domain gets its own certificate. If the domain is already in use on Vercel, the tenant must add a TXT record to prove ownership, and DNS changes can take 24–48 hours to propagate (Vercel docs). Cloudflare for SaaS does the same job in front of any origin, as custom hostnames.
| Question | Vercel for platforms | Cloudflare for SaaS |
|---|---|---|
| How tenant domains are added | Vercel SDK or REST API, per project | Custom hostnames API, in front of your origin |
| TLS | Certificate issued automatically per custom domain; one wildcard for subdomains | Certificates issued per custom hostname |
| Published hostname pricing | See your plan's domain limits | 100 included on Free, Pro and Business, then $0.10 each, up to 50,000; Enterprise custom (Cloudflare plans) |
| Fits when | Your Next.js app is hosted on Vercel | You host elsewhere, or want the edge layer independent of hosting |
Two details that save support tickets. Store domains in your own table with a status (pending, verified, active, failed) and show the tenant exactly which DNS record to add. And if both tenant.yourplatform.com and the custom domain serve the same site, redirect one to the other or set a canonical URL, as Vercel advises, so search engines do not see duplicate content.
Resolving the tenant from the host is one small file. In Next.js 16 it is proxy.ts (middleware.ts in earlier versions):
// proxy.ts: map the incoming host to a tenant route
import { NextResponse, type NextRequest } from 'next/server'
const PLATFORM_HOSTS = new Set(['yourplatform.com', 'www.yourplatform.com', 'app.yourplatform.com'])
export function proxy(req: NextRequest) {
const host = (req.headers.get('host') ?? '').toLowerCase().replace(/:\d+$/, '')
if (PLATFORM_HOSTS.has(host)) return NextResponse.next()
// /sites/[host]/... looks up the tenant by domain on the server and 404s if unknown.
// The host is part of the path, so it is also part of every cache key.
const url = req.nextUrl.clone()
url.pathname = '/sites/' + encodeURIComponent(host) + url.pathname
return NextResponse.rewrite(url)
}
export const config = { matcher: ['/((?!_next|api|favicon.ico).*)'] }
Never take the tenant from a query string or a client header. The host decides the brand; the signed-in membership decides the data.
Cookies on shared subdomains
Browsers treat tenant1.yourplatform.com and tenant2.yourplatform.com as the same site unless your domain is on the Public Suffix List, so one tenant's page could set a cookie that is sent to another's. Vercel recommends submitting the shared domain to the list if tenants can publish content, and in the meantime putting the dashboard and auth on a different apex domain and using host-only cookies prefixed __Host-, with Secure, HttpOnly and Path=/ and no Domain attribute (Vercel docs).
How do you send branded emails from each tenant's domain?
Give every tenant a safe default, and let larger tenants verify their own sending domain.
- Default: send from your platform's domain with the tenant's name as the display name, their reply-to address, and their logo and colours in the template. Nothing for the tenant to configure.
- Own domain: the tenant adds the SPF, DKIM and DMARC records your email provider generates for their domain. Gmail requires senders of more than 5,000 messages a day to use SPF, DKIM and DMARC, to align the From domain with the SPF or DKIM domain, to support one-click unsubscribe on marketing mail, and to keep spam rates below 0.3% (Google sender guidelines). Alignment is what removes the "via" label.
- Reputation is shared until it isn't. One tenant sending poor marketing mail from your shared domain harms every tenant. Separate transactional and marketing streams, and move high-volume tenants onto their own domain.
- Templates per tenant, not per email. One set of templates that reads the tenant's tokens, with an optional override per template for tenants who insist.
How do you keep white-label tenants' data isolated?
Enforce it in the database, so a missed filter in application code returns nothing instead of another tenant's rows. For most white-label products, a shared schema with Postgres row-level security (RLS) is the right default; the trade-offs are in database per tenant vs shared schema.
CREATE TABLE tenants (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
parent_id uuid REFERENCES tenants(id), -- reseller above this tenant, if any
kind text NOT NULL CHECK (kind IN ('platform', 'reseller', 'customer')),
name text NOT NULL,
theme jsonb NOT NULL DEFAULT '{}'
);
CREATE TABLE tenant_domains (
domain text PRIMARY KEY, -- lower-case, no port
tenant_id uuid NOT NULL REFERENCES tenants(id),
status text NOT NULL DEFAULT 'pending'
CHECK (status IN ('pending', 'verified', 'active', 'failed')),
verified_at timestamptz
);
CREATE TABLE projects (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id uuid NOT NULL REFERENCES tenants(id),
name text NOT NULL
);
CREATE INDEX projects_tenant ON projects (tenant_id);
ALTER TABLE projects ENABLE ROW LEVEL SECURITY;
ALTER TABLE projects FORCE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON projects
USING (tenant_id = current_setting('app.tenant_id', true)::uuid)
WITH CHECK (tenant_id = current_setting('app.tenant_id', true)::uuid);
-- Per request, inside the transaction (true = local to this transaction):
-- SELECT set_config('app.tenant_id', $1, true);
The details that decide whether this holds, from the PostgreSQL documentation: superusers and roles with BYPASSRLS always bypass row security, and table owners do too unless the table uses FORCE ROW LEVEL SECURITY. With RLS enabled and no policy, the default is deny, so a forgotten policy fails closed. Set the tenant per transaction, never per pooled connection. The longer walk-through is the Postgres row-level security guide, and if you suspect a leak today, start with users can see other tenants' data.
Sundor Skin, a B2B wholesale platform RAITHub built, isolates every business buyer this way: 146 PostgreSQL tables with row-level security, a CI check that fails the build when a buyer-scoped table lacks a policy, a 21-case IDOR security suite and 530+ automated tests (Sundor Skin case study). It is not a white-label product, but tenant isolation is the same engineering problem.
How should a reseller and partner hierarchy work?
Model it as a tree of tenants (platform, reseller, customer) and keep RLS simple: a session always acts as exactly one tenant. A reseller admin who wants to manage a customer switches into it, after the server checks that the customer sits under that reseller.
- Check the tree on the server. Before setting app.tenant_id to a child, confirm the child's parent chain includes the reseller. A recursive query over tenants.parent_id, or a stored ancestors list, does this.
- Log every switch. "Reseller admin X acted as customer Y" belongs in an append-only audit log the customer can see. The design is in SaaS audit log design.
- Roles are per tenant level. Reseller owner, reseller support, customer admin and customer member are different permission sets; see SaaS authorization and RBAC design.
- Decide who bills whom. Either you bill the reseller wholesale and they bill their customers, or you bill end customers and pay the reseller a share. The first is far simpler to build. Tax treatment differs by country; this is general information, so confirm with your adviser.
- Branding inherits. A customer under a reseller shows the reseller's brand unless the reseller's plan allows sub-branding.
How do per-tenant feature flags and plan limits work?
Resolve each feature from layers, highest first: a platform-wide kill switch, then a tenant override, then the reseller's default, then the plan. Store overrides in a table keyed by tenant and feature, cache the resolved set per tenant for a short time, and check it on the server, never only in the UI.
| Layer | Who sets it | Example |
|---|---|---|
| Platform kill switch | You | Turn off a broken export for everyone, now |
| Tenant override | Your support team | Enable a beta for one large customer |
| Reseller default | The reseller | Hide a module the reseller does not sell |
| Plan | Billing | SSO and custom domains only on the top plan |
Custom domains themselves are usually a plan feature. BlockEstate's partner plans run Free, Starter, Professional and Enterprise, with "White-labeling" listed on Enterprise alongside unlimited API access and custom rate limits (BlockEstate case study).
How long does it take to make an existing SaaS white-label yourself?
If the app is already multi-tenant with tenant IDs on every table: roughly 1–2 weeks for an experienced developer to add host-based tenant resolution, theme tokens, custom domains through Vercel or Cloudflare and branded email defaults. If it is single-tenant today, add 3–6 weeks for the tenancy migration first; the steps are in converting a single-tenant app to multi-tenant. These are our engineering estimates.
The main risk of doing it yourself is a cross-tenant leak outside the database: a cache keyed by path, a cookie scoped to the shared domain, an email template that falls back to another tenant's logo, or a background job that runs without a tenant set. RLS protects the rows; the rest needs tests that sign in as tenant A and try to reach tenant B through every surface.
Why RAITHub for this
- Multi-tenant, with white-label in the plans. BlockEstate is a multi-tenant listing and inquiry platform with each brokerage isolated as a tenant, lead routing and partner plans that include white-labeling at the Enterprise tier. Its MVP shipped in 6 weeks. It has no MLS integration.
- Isolation proven in CI. Sundor Skin runs every buyer query under row-level security, fails the build on a missing policy, and runs 12 staff roles from 88 permission codes.
- Several roles in one codebase. PropDesk serves landlords, tenants, contractors and admins with 1,024 automated tests.
- Next.js and Postgres are home ground. See SaaS development for what a build includes. We sign NDAs and DPAs and work inside your controls.
When you don't need us
- A vendor already sells what your customers need. Reselling a white-label product, such as HighLevel's SaaS Mode for agencies, gets you to market in days.
- You only need your own logo on one product. That is theming for one tenant, not a white-label platform.
- You have fewer than five confirmed reseller customers. Run them on subdomains of one product first; custom domains and reseller hierarchies can wait for demand.
- You need native mobile apps per brand. RAITHub builds web apps and PWAs, not native iOS or Android apps.
How RAITHub would build this
- Scope: tenant model with reseller hierarchy and RLS on every tenant table; host-based tenant resolution with subdomains and custom domains through Vercel or Cloudflare for SaaS; theme tokens across app, emails and PDFs; per-tenant feature flags tied to plans; isolation tests across database, cache, cookies and jobs.
- Timeline: a new white-label SaaS at fixed scope fits the 4–6 week MVP or SaaS range for the first release. Adding white-label to an existing backend, with a tenancy migration, is backend work in the 6–12 week range. If an existing white-label product is leaking data or failing, a code rescue takes 2–4 weeks.
- You receive: automated tests and CI, including cross-tenant tests that run on every build; handover docs and runbooks for onboarding a tenant, adding a domain and offboarding; full IP under NDA.
- Next step: a free 15-minute technical audit of your product and reseller plans, then a written fixed quote. Book the audit, or read the SaaS industry page first.
Frequently asked questions
What is a white-label SaaS platform?
A multi-tenant software product that customers or resellers run under their own brand, with their logo, colours, domain and email, while one codebase serves everyone and the database keeps each tenant's data separate.
How do custom domains work in a white-label SaaS?
Your code adds the tenant's domain through a platform API, such as the Vercel SDK or Cloudflare for SaaS custom hostnames, the tenant proves ownership with a DNS record, and a TLS certificate is issued automatically. Cloudflare for SaaS includes 100 hostnames, then $0.10 each.
Do I need a separate database for each white-label client?
Usually not. A shared schema with Postgres row-level security suits most white-label products and keeps one migration for everyone. A database per tenant fits a few large clients whose contracts require physical separation.
How do I send emails from each tenant's own domain?
Start by sending from your domain with the tenant's name, reply-to and branding. For tenants who want their own domain, have them add SPF, DKIM and DMARC records; Gmail requires all three, and From-domain alignment, for senders of more than 5,000 messages a day.
How do resellers manage their own customers safely?
Model tenants as a tree, let a reseller admin switch into one child tenant at a time after the server checks the hierarchy, and record every switch in an audit log the customer can see. Row-level security then only ever deals with one tenant per request.
How long does it take to build a white-label SaaS?
A first release at fixed scope fits RAITHub's 4–6 week SaaS and MVP range. Converting an existing single-tenant product typically takes longer, in the 6–12 week backend range, because the tenancy migration comes first.
Related posts
Ready to discuss your project?
Book a free 15-minute technical audit with our engineering team.