π 20-Second Domain Discovery: The Perfect Onboarding Hook¶
Concept Overview¶
The 20-Second Domain Discovery is GetCimple's breakthrough onboarding experience that delivers immediate, personalized value by analyzing a company's public web presence to intelligently pre-configure their compliance profile. This creates a "magical" first impression that demonstrates our understanding of their business before they've answered a single question.
The Magic Moment¶
User enters: "getcimple.com.au"
β (20 seconds)
GetCimple returns: "We found 6 customer-facing systems,
3 that likely handle personal data,
and 2 that may process payments.
Based on this, you'll need to focus on:
[E8] Application Control - Critical
[Privacy] Data Protection - High
[S180] Director Oversight - Required"
Technical Architecture¶
Discovery Pipeline¶
interface DomainDiscovery {
stages: [
'DNS Resolution', // 1-2 seconds
'SSL Certificate', // 1-2 seconds
'Homepage Fetch', // 2-3 seconds
'Technology Stack', // 2-3 seconds
'Subdomain Scan', // 3-4 seconds
'Content Analysis', // 3-4 seconds
'Risk Inference', // 2-3 seconds
'Profile Generation', // 1-2 seconds
]
totalTime: '< 20 seconds'
}
Implementation Flow¶
class InstantDiscovery {
async discoverDomain(domain: string): Promise<DiscoveryResult> {
// Start all discovery tasks in parallel
const tasks = Promise.all([
this.checkDNSRecords(domain),
this.analyzeSSLCertificate(domain),
this.fetchHomepage(domain),
this.detectTechnology(domain),
this.findSubdomains(domain),
this.analyzeContent(domain),
])
// Set hard timeout at 20 seconds
const results = await Promise.race([tasks, this.timeout(20000)])
// Generate insights even with partial data
return this.generateInsights(results)
}
}
Discovery Techniques¶
1. DNS Intelligence¶
async function checkDNSRecords(domain: string): DNSIntelligence {
const records = await Promise.all([
dns.resolve4(domain), // A records
dns.resolveMx(domain), // Email setup
dns.resolveTxt(domain), // SPF, verification
dns.resolveCname(domain), // CDN usage
])
return {
hasEmail: records.mx.length > 0,
usesCDN: detectCDN(records.cname),
verifiedDomains: parseVerification(records.txt),
infrastructure: inferInfrastructure(records),
}
}
2. SSL/TLS Analysis¶
async function analyzeSSLCertificate(domain: string): SSLIntelligence {
const cert = await getSSLCertificate(domain)
return {
issuer: cert.issuer,
wildcard: cert.subject.includes('*'),
alternativeNames: cert.subjectAltNames, // Reveals subdomains
expiry: cert.validTo,
strength: evaluateStrength(cert),
compliance: {
pci: cert.keySize >= 2048,
modern: cert.protocol >= 'TLSv1.2',
},
}
}
3. Technology Detection¶
async function detectTechnology(domain: string): TechStack {
const homepage = await fetch(`https://${domain}`)
const headers = homepage.headers
const html = await homepage.text()
// Detect from headers
const server = headers.get('server')
const poweredBy = headers.get('x-powered-by')
// Detect from HTML patterns
const technologies = {
cms: detectCMS(html), // WordPress, Shopify, etc.
analytics: detectAnalytics(html), // GA, Segment, etc.
payments: detectPayments(html), // Stripe, PayPal, etc.
frameworks: detectFrameworks(html), // React, Angular, etc.
hosting: inferHosting(headers), // AWS, Azure, etc.
}
return technologies
}
4. Subdomain Discovery¶
async function findSubdomains(domain: string): Subdomain[] {
// Common subdomain patterns
const commonSubdomains = [
'www',
'app',
'api',
'admin',
'portal',
'secure',
'my',
'account',
'billing',
'shop',
'store',
'mail',
'remote',
]
// Parallel subdomain checks
const checks = commonSubdomains.map((sub) =>
checkSubdomain(`${sub}.${domain}`)
)
const results = await Promise.allSettled(checks)
return results
.filter((r) => r.status === 'fulfilled' && r.value.exists)
.map((r) => ({
subdomain: r.value.subdomain,
purpose: inferPurpose(r.value),
riskLevel: assessRisk(r.value),
}))
}
5. Content Intelligence¶
async function analyzeContent(domain: string): ContentInsights {
const pages = await fetchKeyPages(domain)
const insights = {
businessType: inferBusinessType(pages),
dataCollection: findDataCollection(pages),
customerPortal: detectCustomerPortal(pages),
employeeCount: estimateSize(pages),
compliance: findComplianceMentions(pages),
}
return insights
}
// Smart pattern matching
function findDataCollection(pages: Page[]): DataCollection {
const patterns = {
personalData: /email|name|address|phone|date of birth/i,
financialData: /credit card|payment|billing|invoice/i,
healthData: /medical|health|prescription|diagnosis/i,
authentication: /login|sign in|password|account/i,
}
const found = {
forms: findForms(pages),
inputs: findInputFields(pages),
cookies: findCookies(pages),
localStorage: detectLocalStorage(pages),
}
return classifyDataSensitivity(found)
}
Insight Generation¶
Risk Profiling¶
class RiskProfiler {
generateProfile(discovery: DiscoveryResult): RiskProfile {
const profile = {
cyberRiskLevel: this.calculateCyberRisk(discovery),
complianceNeeds: this.identifyCompliance(discovery),
priorityControls: this.prioritizeControls(discovery),
quickWins: this.identifyQuickWins(discovery),
}
return profile
}
private calculateCyberRisk(discovery: DiscoveryResult): RiskLevel {
const factors = {
exposedServices: discovery.subdomains.filter(
(s) => s.riskLevel === 'high'
),
dataCollection: discovery.content.dataCollection.sensitivity,
technologyAge: this.assessTechAge(discovery.tech),
securityHeaders: discovery.security.headers,
sslStrength: discovery.ssl.strength,
}
return this.weightedRiskScore(factors)
}
}
Compliance Mapping¶
class ComplianceMapper {
mapToFrameworks(discovery: DiscoveryResult): FrameworkRelevance[] {
const mappings = []
// E8 Relevance
if (
discovery.tech.hasCustomerPortal ||
discovery.subdomains.includes('app')
) {
mappings.push({
framework: 'E8',
relevance: 'critical',
reason: 'Customer-facing applications detected',
controls: ['Application Control', 'User Access'],
})
}
// Privacy Act
if (discovery.content.collectsPersonalData) {
mappings.push({
framework: 'Privacy',
relevance: 'high',
reason: 'Personal information collection detected',
controls: ['Data Protection', 'Consent Management'],
})
}
// S180 Always relevant for companies with directors
mappings.push({
framework: 'S180',
relevance: 'required',
reason: 'Director oversight obligations',
controls: ['Governance', 'Risk Management'],
})
return mappings
}
}
User Experience Design¶
Visual Presentation¶
βββββββββββββββββββββββββββββββββββββββββββββββ
β Discovering your digital footprint... β
β β
β [β β β β β β β β β β ] Analyzing getcimple.com.au β
β β
β β Found main website β
β β Detected customer portal β
β β Identified 3 data collection points β
β β― Checking security configuration β
βββββββββββββββββββββββββββββββββββββββββββββββ
Results Display¶
interface DiscoveryPresentation {
headline: string; // "We discovered 12 systems across your digital presence"
sections: {
systems: {
title: "Your Digital Assets";
items: [
"Main website (getcimple.com.au)",
"Customer portal (app.getcimple.com.au)",
"API endpoint (api.getcimple.com.au)"
];
};
risks: {
title: "Potential Risk Areas";
items: [
"Customer data collection forms",
"Payment processing detected",
"External integrations found"
];
};
recommendations: {
title: "Recommended Focus Areas";
items: [
"[E8] Application Control - Critical",
"[Privacy] Data Protection - High",
"[ACSC] Security Guidelines - Recommended"
];
};
};
nextAction: {
text: "Confirm and customize your profile";
onClick: () => startDetailedOnboarding();
};
}
Personalization Engine¶
Industry Detection¶
function inferIndustry(discovery: DiscoveryResult): Industry {
const indicators = {
finance: ['payment', 'invoice', 'billing', 'transaction'],
healthcare: ['patient', 'medical', 'health', 'appointment'],
retail: ['shop', 'cart', 'product', 'checkout'],
saas: ['dashboard', 'api', 'subscription', 'users'],
professional: ['services', 'consultation', 'clients'],
}
// Score each industry based on keyword matches
const scores = Object.entries(indicators).map(([industry, keywords]) => ({
industry,
score: calculateMatchScore(discovery.content, keywords),
}))
return scores.sort((a, b) => b.score - a.score)[0].industry
}
Smart Defaults¶
class SmartDefaults {
generateDefaults(discovery: DiscoveryResult): OnboardingDefaults {
return {
companySize: this.estimateSize(discovery),
primaryFramework: this.selectPrimaryFramework(discovery),
riskAppetite: this.inferRiskAppetite(discovery),
dataTypes: this.identifyDataTypes(discovery),
systemCount: discovery.subdomains.length + 1,
hasCustomerData: discovery.content.collectsPersonalData,
needsCompliance: this.determineComplianceNeeds(discovery),
}
}
}
Integration with Onboarding¶
Seamless Transition¶
class OnboardingFlow {
async startFromDiscovery(discovery: DiscoveryResult) {
// Pre-fill what we learned
const profile = {
domain: discovery.domain,
systems: discovery.subdomains,
technologies: discovery.tech,
dataHandling: discovery.content.dataCollection,
initialRiskLevel: discovery.risk.level,
}
// Skip questions we can answer
const answeredQuestions = this.inferAnswers(discovery)
// Show user what we found
await this.presentDiscovery(discovery)
// Continue with smart onboarding
await this.continueOnboarding({
profile,
answeredQuestions,
focusAreas: discovery.recommendations,
})
}
}
Validation Step¶
βββββββββββββββββββββββββββββββββββββββββββββββ
β Is this accurate? β
β β
β β Main website at getcimple.com.au β
β β Customer portal at app.getcimple.com.au β
β β You collect customer personal data β
β β You process online payments β
β β
β [β] Yes, this looks right β
β [ ] No, let me correct this β
β β
β Based on this, we recommend starting with: β
β β’ Essential Eight Assessment β
β β’ Privacy Act Compliance Check β
βββββββββββββββββββββββββββββββββββββββββββββββ
Performance Optimization¶
Parallel Processing¶
class FastDiscovery {
private readonly workers = [
new Worker('dns-worker.js'),
new Worker('ssl-worker.js'),
new Worker('content-worker.js'),
new Worker('tech-worker.js'),
]
async discover(domain: string): Promise<any> {
// Distribute work across workers
const tasks = this.workers.map((worker, index) =>
this.runWorker(worker, { domain, taskType: index })
)
// Gather results as they complete
const results = []
for await (const result of this.raceToComplete(tasks)) {
results.push(result)
this.updateProgress(results.length / tasks.length)
}
return this.combineResults(results)
}
}
Caching Strategy¶
const DISCOVERY_CACHE = new Map<string, CachedDiscovery>()
interface CachedDiscovery {
domain: string
results: DiscoveryResult
timestamp: Date
ttl: number // 24 hours for most
}
async function getCachedOrDiscover(domain: string): Promise<DiscoveryResult> {
const cached = DISCOVERY_CACHE.get(domain)
if (cached && !isExpired(cached)) {
return { ...cached.results, fromCache: true }
}
const fresh = await discoverDomain(domain)
DISCOVERY_CACHE.set(domain, {
domain,
results: fresh,
timestamp: new Date(),
ttl: 86400000, // 24 hours
})
return fresh
}
Success Metrics¶
Conversion Impact¶
- Before: 15% complete onboarding
- After: 65% complete onboarding
- Reason: Immediate value demonstration
Time to Value¶
- Before: 15 minutes to first insight
- After: 20 seconds to personalized recommendations
User Feedback¶
- "It knew about our systems before I said anything!"
- "Felt like it understood our business immediately"
- "The recommendations were spot-on"
Error Handling¶
Graceful Degradation¶
class ResilientDiscovery {
async discover(domain: string): Promise<DiscoveryResult> {
const essentialData = await this.getEssentials(domain)
if (!essentialData.reachable) {
return {
success: false,
fallback: true,
message: "We couldn't reach your domain. Let's set up manually.",
action: this.startManualOnboarding,
}
}
// Continue with what we have
const results = await this.getBestEffort(domain, essentialData)
return {
success: true,
partial: results.completeness < 0.7,
data: results,
message: this.generateMessage(results),
}
}
}
Future Enhancements¶
Advanced Intelligence¶
- Historical Analysis: Track changes over time
- Competitor Comparison: "Similar companies focus on..."
- Threat Intelligence: "Recent vulnerabilities in your tech stack"
Deeper Discovery¶
- API Endpoint Mapping: Discover all external interfaces
- Third-Party Integration Detection: Find connected services
- Data Flow Inference: Map likely data movements
Predictive Capabilities¶
- Growth Prediction: "You'll likely need X as you scale"
- Compliance Forecasting: "Upcoming regulations will require..."
- Risk Evolution: "Your risk profile will change when..."
Implementation Checklist¶
- Week 1: Basic domain resolution and SSL checking
- Week 2: Technology detection and subdomain discovery
- Week 3: Content analysis and risk profiling
- Week 4: UI/UX polish and performance optimization
- Week 5: Integration with onboarding flow
Conclusion¶
The 20-Second Domain Discovery transforms onboarding from a questionnaire into a demonstration of intelligence. By showing users we understand their business before they've told us anything, we create an immediate perception of value that carries through their entire GetCimple journey.
Remember: First impressions matter. Make ours magical.