Engineering

Domain Validation: How It Works and Why It Matters for Software Licensing

TOT
Traffic Orchestrator Team
Engineering
March 16, 2026 10 min read 635 words
Share

Domain validation is the mechanism that ties a software license to a specific website. For SaaS embeds, WordPress plugins, JavaScript libraries, and API integrations, domain validation is the most reliable method of preventing unauthorized use. But the implementation details make or break the system.

How Domain Validation Works

  1. Extraction — Your software extracts the current hostname from the runtime environment
  2. Transmission — The hostname and license key are sent to your validation API
  3. Matching — Your server checks if the domain is authorized for this key
  4. Response — Valid or invalid, with details about the license status
// Client-side domain extraction
const currentDomain = window.location.hostname // "app.example.com"

// Server-side validation
const isValid = await validateLicense({
  key: customerKey,
  domain: currentDomain
})
// Returns: { valid: true, licensedTo: "example.com", plan: "professional" }

Domain Matching Strategies

Exact Match

The simplest approach: the domain must match exactly. example.com only matches example.com — not www.example.com or app.example.com.

When to use: When you want strict control over exactly which domain uses the license.

Root Domain Match

Normalize all subdomains to the root domain. app.example.com, www.example.com, and example.com all match a license for example.com.

// Root domain extraction
const getRootDomain = (hostname) => {
  const parts = hostname.split('.')
  // Handle 2-part TLDs like .co.uk, .com.au
  const twoPartTLDs = ['co.uk', 'com.au', 'co.nz', 'com.br', 'co.jp']
  const suffix = parts.slice(-2).join('.')
  if (twoPartTLDs.includes(suffix)) return parts.slice(-3).join('.')
  return parts.slice(-2).join('.')
}

getRootDomain('app.staging.example.com') // "example.com"
getRootDomain('shop.example.co.uk')      // "example.co.uk"

When to use: For most SaaS licensing. This is the most customer-friendly approach — they register one domain and all subdomains work.

Wildcard Pattern Match

Allow wildcard patterns like *.example.com for customers who need specific subdomain control. Useful for multi-tenant platforms where each tenant has their own subdomain.

Handling Edge Cases

www vs non-www

Always normalize. www.example.com and example.com should be treated as the same domain. Strip the www. prefix during validation.

Localhost and Development

Don't force developers to burn a domain slot for local development. Whitelist these development domains globally:

  • localhost and 127.0.0.1
  • *.local and *.test
  • *.localhost
  • Common dev tools: *.ngrok.io, *.vercel.app (configurable)

Staging Environments

Production licenses should work on staging by default. Match staging.example.com against a license for example.com using root domain matching.

IP Addresses

Some customers access applications by IP address during development or on internal networks. Support IP-based validation alongside domain matching.

Internationalized Domain Names (IDN)

Domains like 例え.jp use Punycode encoding (xn--r8jz45g.jp). Always validate against the Punycode form to avoid encoding mismatches.

Server-Side Verification

Client-side domain extraction (window.location.hostname) can be spoofed in browser extensions or modified clients. For critical validation, verify the domain server-side using:

  • Referer/Origin headers — Check the HTTP headers for the requesting domain
  • DNS TXT records — Require customers to add a TXT record proving domain ownership
  • Server-side callbacks — Your customer's server validates, not the browser
// Server-side origin verification
const validateRequest = (request) => {
  const origin = request.headers.get('Origin') || request.headers.get('Referer')
  if (!origin) return { valid: false, error: 'Missing origin header' }
  
  const requestDomain = new URL(origin).hostname
  const rootDomain = getRootDomain(requestDomain)
  
  // Check if root domain is authorized for this license
  return checkLicenseDomain(licenseKey, rootDomain)
}

Domain Activation Limits

Set per-license domain limits that scale with your pricing tiers:

PlanDomain LimitBest For
Builder (Free)1 domainSide projects, testing
Starter3 domainsIndividual developers
Professional10 domainsSmall teams, agencies
Business50 domainsGrowing companies
EnterpriseUnlimitedLarge organizations

Performance: Edge Validation

Domain validation runs on every page load or API call from your customer's application. Latency must be under 10ms. Deploy your validation logic at the edge — close to your customers — with aggressive caching of license-domain mappings.

  • Cache valid licenses for 5-15 minutes at each edge location
  • Cache invalid results for 1 minute (allows quick recovery after activation)
  • Use stale-while-revalidate — serve cached results while refreshing in the background
TOT
Traffic Orchestrator Team
Engineering

The engineering team behind Traffic Orchestrator, building enterprise-grade software licensing infrastructure used by developers worldwide.

Was this article helpful?
Get licensing insights delivered

Engineering deep-dives, security advisories, and product updates. Unsubscribe anytime.

Share this article
Free Plan Available

Ship licensing in your next release

5 licenses, 500 validations/month, full API access. Set up in under 5 minutes — no credit card required.

2-minute setup No credit card Cancel anytime