---
title: "White Label"
description: "White Label documentation for Ring Platform"
locale: "en"
---
# White Label Examples

Complete white-labeling and customization examples for agencies and enterprises building with Ring Platform.

## 🎨 Brand Customization

### Complete Brand Override

// lib/brand-config.ts

{`export interface BrandConfig {
  name: string
  logo: {
    light: string
    dark: string
    favicon: string
  }
  colors: {
    primary: string
    secondary: string
    accent: string
    background: string
    foreground: string
  }
  typography: {
    fontFamily: string
    headingFont?: string
  }
  domain: string
  contact: {
    email: string
    phone?: string
    address?: string
  }
}

// Example brand configurations
export const brandConfigs: Record<string, BrandConfig> = {
  'tech-startup': {
    name: 'TechConnect',
    logo: {
      light: '/brands/techconnect/logo-light.svg',
      dark: '/brands/techconnect/logo-dark.svg',
      favicon: '/brands/techconnect/favicon.ico'
    },
    colors: {
      primary: '#3B82F6',
      secondary: '#8B5CF6',
      accent: '#10B981',
      background: '#FFFFFF',
      foreground: '#1F2937'
    },
    typography: {
      fontFamily: 'Inter, sans-serif',
      headingFont: 'Poppins, sans-serif'
    },
    domain: 'techconnect.com',
    contact: {
      email: 'hello@techconnect.com',
      phone: '+1 (555) 123-4567'
    }
  },
  'healthcare-network': {
    name: 'MedConnect',
    logo: {
      light: '/brands/medconnect/logo-light.svg',
      dark: '/brands/medconnect/logo-dark.svg',
      favicon: '/brands/medconnect/favicon.ico'
    },
    colors: {
      primary: '#059669',
      secondary: '#0891B2',
      accent: '#DC2626',
      background: '#F9FAFB',
      foreground: '#111827'
    },
    typography: {
      fontFamily: 'Source Sans Pro, sans-serif',
      headingFont: 'Merriweather, serif'
    },
    domain: 'medconnect.health',
    contact: {
      email: 'support@medconnect.health',
      phone: '+1 (555) 987-6543'
    }
  }
}

// Brand context provider
export function getBrandConfig(domain: string): BrandConfig {
  // In production, this would be determined by the domain
  const subdomain = domain.split('.')[0]
  return brandConfigs[subdomain] || brandConfigs['tech-startup']
}`}

### Dynamic Brand Provider

// components/BrandProvider.tsx

{`'use client'

import { createContext, useContext, useEffect, useState } from 'react'
import { BrandConfig, getBrandConfig } from '@/lib/brand-config'

const BrandContext = createContext(null)

export function BrandProvider({ children }: { children: React.ReactNode }) {
  const [brand, setBrand] = useState(null)

  useEffect(() => {
    // Get brand config based on current domain
    const domain = window.location.hostname
    const config = getBrandConfig(domain)
    setBrand(config)

    // Apply brand styles dynamically
    applyBrandStyles(config)
  }, [])

  const applyBrandStyles = (config: BrandConfig) => {
    const root = document.documentElement

    // Apply CSS custom properties
    root.style.setProperty('--brand-primary', config.colors.primary)
    root.style.setProperty('--brand-secondary', config.colors.secondary)
    root.style.setProperty('--brand-accent', config.colors.accent)
    root.style.setProperty('--brand-background', config.colors.background)
    root.style.setProperty('--brand-foreground', config.colors.foreground)
    root.style.setProperty('--brand-font', config.typography.fontFamily)
    
    if (config.typography.headingFont) {
      root.style.setProperty('--brand-heading-font', config.typography.headingFont)
    }

    // Update document title and favicon
    document.title = `${config.name} - Professional Networking Platform`
    
    const favicon = document.querySelector('link[rel="icon"]') as HTMLLinkElement
    if (favicon) {
      favicon.href = config.logo.favicon
    }
  }

  if (!brand) {
    return Loading brand configuration...
  }

  return (
    
      {children}
    
  )
}

export function useBrand() {
  const context = useContext(BrandContext)
  if (!context) {
    throw new Error('useBrand must be used within a BrandProvider')
  }
  return context
}`}

### Branded Header Component

// components/BrandedHeader.tsx

{`'use client'

import { useBrand } from './BrandProvider'
import { useSession, signIn, signOut } from 'next-auth/react'

export function BrandedHeader() {
  const brand = useBrand()
  const { data: session } = useSession()

  return (
    
      
        
          {/* Brand Logo */}
          
            
            
            
              {brand.name}
            
          

          {/* Navigation */}
          
            
              Organizations
            
            
              Opportunities
            
            
              Marketplace
            
          

          {/* User Menu */}
          
            {session ? (
              
                
                  Welcome, {session.user?.name}
                
                 signOut()}
                  className="text-sm text-gray-500 hover:text-gray-700"
                >
                  Sign Out
                
              
            ) : (
               signIn()}
                className="px-4 py-2 rounded-md text-white font-medium"
                style={{ backgroundColor: brand.colors.primary }}
              >
                Sign In
              
            )}
          
        
      
    
  )
}`}

## 🏢 Multi-Tenant Architecture

### Tenant Configuration

// lib/tenant-config.ts

{`export interface TenantConfig {
  id: string
  name: string
  domain: string
  subdomain: string
  brand: BrandConfig
  features: {
    entities: boolean
    opportunities: boolean
    messaging: boolean
    wallet: boolean
    store: boolean
    nftMarketplace: boolean
    staking: boolean
  }
  limits: {
    maxEntities: number
    maxUsers: number
    storageGB: number
  }
  integrations: {
    customDomain: boolean
    sso: boolean
    api: boolean
    webhooks: boolean
  }
  subscription: {
    plan: 'starter' | 'professional' | 'enterprise'
    status: 'active' | 'suspended' | 'cancelled'
    expiresAt: string
  }
}

export const tenantConfigs: Record<string, TenantConfig> = {
  'tech-startup': {
    id: 'tech-startup-001',
    name: 'TechConnect',
    domain: 'techconnect.com',
    subdomain: 'techconnect',
    brand: brandConfigs['tech-startup'],
    features: {
      entities: true,
      opportunities: true,
      messaging: true,
      wallet: true,
      store: false,
      nftMarketplace: false,
      staking: false
    },
    limits: {
      maxEntities: 1000,
      maxUsers: 5000,
      storageGB: 100
    },
    integrations: {
      customDomain: true,
      sso: true,
      api: true,
      webhooks: true
    },
    subscription: {
      plan: 'professional',
      status: 'active',
      expiresAt: '2024-12-31T23:59:59Z'
    }
  }
}

export function getTenantConfig(domain: string): TenantConfig | null {
  const subdomain = domain.split('.')[0]
  return tenantConfigs[subdomain] || null
}`}

### Feature Gate Component

// components/FeatureGate.tsx

{`'use client'

import { useTenant } from '@/hooks/useTenant'

interface FeatureGateProps {
  feature: keyof TenantConfig['features']
  children: React.ReactNode
  fallback?: React.ReactNode
}

export function FeatureGate({ feature, children, fallback }: FeatureGateProps) {
  const tenant = useTenant()

  if (!tenant?.features[feature]) {
    return fallback || (
      
        
          This feature is not available in your current plan.
        
        
          Upgrade Plan
        
      
    )
  }

  return <>{children}</>
}

// Usage example
export function Dashboard() {
  return (
    
      
        Organizations
        Manage your organizations and teams.
      

      
        
          Wallet
          Manage your crypto wallet and tokens.
        
      

      
        
          Marketplace
          Buy and sell products and services.
        
      
    
  )
}`}

## 🎯 Custom Domain Setup

### Domain Configuration

// lib/domain-config.ts

{`export interface DomainConfig {
  domain: string
  tenantId: string
  ssl: {
    enabled: boolean
    certificate?: string
    privateKey?: string
  }
  dns: {
    verified: boolean
    records: Array<{
      type: 'A' | 'CNAME' | 'TXT'
      name: string
      value: string
      ttl: number
    }>
  }
  status: 'pending' | 'active' | 'failed'
}

export async function setupCustomDomain(
  tenantId: string,
  domain: string
): Promise {
  // Verify domain ownership
  const verificationToken = generateVerificationToken()
  
  const config: DomainConfig = {
    domain,
    tenantId,
    ssl: {
      enabled: false
    },
    dns: {
      verified: false,
      records: [
        {
          type: 'CNAME',
          name: domain,
          value: 'ring-platform.vercel.app',
          ttl: 300
        },
        {
          type: 'TXT',
          name: `_ring-verification.${domain}`,
          value: verificationToken,
          ttl: 300
        }
      ]
    },
    status: 'pending'
  }

  // Save configuration
  await saveDomainConfig(config)
  
  // Start verification process
  await verifyDomainOwnership(config)
  
  return config
}

async function verifyDomainOwnership(config: DomainConfig): Promise {
  // Implementation would check DNS records
  // This is a simplified example
  return true
}

function generateVerificationToken(): string {
  return Math.random().toString(36).substring(2, 15) + 
         Math.random().toString(36).substring(2, 15)
}

async function saveDomainConfig(config: DomainConfig): Promise {
  // Save to database
}`}

### Domain Setup Component

// components/DomainSetup.tsx

{`'use client'

import { useState } from 'react'
import { setupCustomDomain } from '@/lib/domain-config'

export function DomainSetup() {
  const [domain, setDomain] = useState('')
  const [loading, setLoading] = useState(false)
  const [config, setConfig] = useState(null)

  const handleSetupDomain = async (e: React.FormEvent) => {
    e.preventDefault()
    setLoading(true)

    try {
      const domainConfig = await setupCustomDomain('current-tenant-id', domain)
      setConfig(domainConfig)
    } catch (error) {
      console.error('Failed to setup domain:', error)
      alert('Failed to setup custom domain')
    } finally {
      setLoading(false)
    }
  }

  return (
    
      Custom Domain Setup

      {!config ? (
        
          
            
              Custom Domain
            
             setDomain(e.target.value)}
              placeholder="yourdomain.com"
              className="w-full p-3 border border-gray-300 rounded-lg"
              required
            />
            
              Enter your custom domain without http:// or https://
            
          

          
            {loading ? 'Setting up domain...' : 'Setup Custom Domain'}
          
        
      ) : (
        
          
            
              DNS Configuration Required
            
            
              Please add the following DNS records to your domain:
            

            
              {config.dns.records.map((record, index) => (
                
                  
                    
                      Type: {record.type}
                    
                    
                      Name: {record.name}
                    
                    
                      Value: 
                      
                        {record.value}
                      
                    
                    
                      TTL: {record.ttl}
                    
                  
                
              ))}
            
          

          
            Next Steps
            
              Add the DNS records to your domain provider
              Wait for DNS propagation (up to 24 hours)
              We'll automatically verify and activate your domain
              SSL certificate will be provisioned automatically
            
          

          
            
              
              
                Status: {config.status.charAt(0).toUpperCase() + config.status.slice(1)}
              
            

             window.location.reload()}
              className="text-blue-600 hover:text-blue-800 text-sm"
            >
              Check Status
            
          
        
      )}
    
  )
}`}

## 🔧 Environment Configuration

### Multi-Environment Setup

// lib/env-config.ts

{`export interface EnvironmentConfig {
  name: 'development' | 'staging' | 'production'
  api: {
    baseUrl: string
    timeout: number
    retries: number
  }
  database: {
    url: string
    ssl: boolean
  }
  auth: {
    providers: string[]
    sessionTimeout: number
  }
  features: {
    debug: boolean
    analytics: boolean
    errorTracking: boolean
  }
  integrations: {
    stripe: boolean
    sendgrid: boolean
    aws: boolean
  }
}

export const environments: Record<string, EnvironmentConfig> = {
  development: {
    name: 'development',
    api: {
      baseUrl: 'http://localhost:3000/api',
      timeout: 10000,
      retries: 3
    },
    database: {
      url: process.env.DATABASE_URL || 'postgresql://localhost:5432/ring_dev',
      ssl: false
    },
    auth: {
      providers: ['email', 'google'],
      sessionTimeout: 24 * 60 * 60 // 24 hours
    },
    features: {
      debug: true,
      analytics: false,
      errorTracking: false
    },
    integrations: {
      stripe: false,
      sendgrid: false,
      aws: false
    }
  },
  production: {
    name: 'production',
    api: {
      baseUrl: 'https://your-clone.example/api',
      timeout: 5000,
      retries: 5
    },
    database: {
      url: process.env.DATABASE_URL!,
      ssl: true
    },
    auth: {
      providers: ['email', 'google', 'apple', 'metamask'],
      sessionTimeout: 7 * 24 * 60 * 60 // 7 days
    },
    features: {
      debug: false,
      analytics: true,
      errorTracking: true
    },
    integrations: {
      stripe: true,
      sendgrid: true,
      aws: true
    }
  }
}

export function getEnvironmentConfig(): EnvironmentConfig {
  const env = process.env.NODE_ENV as keyof typeof environments
  return environments[env] || environments.development
}`}

### Environment-Specific Components

// components/EnvironmentBanner.tsx

{`'use client'

import { getEnvironmentConfig } from '@/lib/env-config'

export function EnvironmentBanner() {
  const config = getEnvironmentConfig()

  if (config.name === 'production') {
    return null
  }

  const bannerColors = {
    development: 'bg-green-600',
    staging: 'bg-yellow-600'
  }

  return (
    
      
        {config.name.toUpperCase()} ENVIRONMENT
      
      {config.features.debug && ' - Debug Mode Enabled'}
    
  )
}

// components/ConditionalFeature.tsx
interface ConditionalFeatureProps {
  environment: 'development' | 'staging' | 'production'
  children: React.ReactNode
}

export function ConditionalFeature({ environment, children }: ConditionalFeatureProps) {
  const config = getEnvironmentConfig()

  if (config.name !== environment) {
    return null
  }

  return <>{children}</>
}

// Usage
export function AdminPanel() {
  return (
    
      Admin Panel
      
      
        
          Development Only: Debug tools and test data controls
        
      

      {/* Regular admin content */}
    
  )
}`}

## 📊 Analytics & Tracking

### Custom Analytics Setup

// lib/analytics.ts

{`export interface AnalyticsEvent {
  name: string
  properties?: Record<string, any>
  userId?: string
  tenantId?: string
  timestamp?: string
}

export class Analytics {
  private tenantId: string
  private userId?: string

  constructor(tenantId: string, userId?: string) {
    this.tenantId = tenantId
    this.userId = userId
  }

  track(event: AnalyticsEvent) {
    const enrichedEvent = {
      ...event,
      tenantId: this.tenantId,
      userId: this.userId || event.userId,
      timestamp: new Date().toISOString(),
      properties: {
        ...event.properties,
        url: window.location.href,
        userAgent: navigator.userAgent,
        referrer: document.referrer
      }
    }

    // Send to analytics service
    this.sendEvent(enrichedEvent)
  }

  private async sendEvent(event: AnalyticsEvent) {
    try {
      await fetch('/api/analytics/track', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(event)
      })
    } catch (error) {
      console.error('Analytics tracking failed:', error)
    }
  }

  // Predefined events
  trackPageView(page: string) {
    this.track({
      name: 'page_view',
      properties: { page }
    })
  }

  trackEntityCreated(entityType: string) {
    this.track({
      name: 'entity_created',
      properties: { entityType }
    })
  }

  trackOpportunityApplied(opportunityId: string, opportunityType: string) {
    this.track({
      name: 'opportunity_applied',
      properties: { opportunityId, opportunityType }
    })
  }

  trackWalletConnected(walletType: string) {
    this.track({
      name: 'wallet_connected',
      properties: { walletType }
    })
  }
}

// Analytics hook
export function useAnalytics() {
  const tenant = useTenant()
  const { data: session } = useSession()

  return new Analytics(tenant?.id || 'unknown', session?.user?.id)
}`}

---

*Ready to see complete implementations? Check out [Real World Apps](/en/docs/examples/real-world) or explore our [API Integration](/en/docs/examples/api-integration) examples.*
