Skip to main content
Learn how to build a brand name availability checker for startups, naming agencies, and entrepreneurs.

Overview

This guide shows you how to validate brand names against trademark databases across multiple jurisdictions, helping businesses choose safe, available names. What you’ll build:
  • Real-time name availability checking
  • Multi-jurisdiction validation (US, EU, UK)
  • Visual risk indicators
  • Detailed conflict analysis
  • Nice class mapping from business descriptions
Time to complete: 30 minutes

Use Case: Startup Naming Tool

You’re building a tool for entrepreneurs to validate their startup names before incorporating or filing trademarks.

The Problem

Entrepreneurs often:
  • Choose names without checking trademarks
  • Discover conflicts after incorporation
  • Face expensive rebranding
  • Don’t know which jurisdictions to check
  • Waste time and money on unavailable names

The Solution

Validate brand names across multiple jurisdictions before committing to them.

Step 1: Determine Relevant Trademark Classes

First, classify the business to determine which Nice classes are relevant.
async function getRelevantClasses(businessDescription) {
  const response = await fetch('https://api.signa.so/v1/analysis/classify', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.TRADEMARK_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      text: businessDescription
    })
  });

  return await response.json();
}

Example Request

const classification = await getRelevantClasses(
  'SaaS platform for workflow automation'
);

// Returns:
{
  "suggested_classes": [
    {
      "class_number": 9,
      "name": "Computer software",
      "reason": "Software products and downloadable applications",
      "confidence": 0.92
    },
    {
      "class_number": 42,
      "name": "Software as a service (SaaS)",
      "reason": "Cloud-based software services",
      "confidence": 0.95
    }
  ]
}

Step 2: Check Brand Name in Those Classes

Now run the fast conflict check with the brand name and relevant classes.
async function checkBrandName(name, classes, jurisdictions = ['US', 'EU', 'UK']) {
  const response = await fetch('https://api.signa.so/v1/analysis/check', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.TRADEMARK_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      text: name,
      classes: classes,
      jurisdictions: jurisdictions
    })
  });

  return await response.json();
}

Example Request

// First, get classes
const classification = await getRelevantClasses('SaaS platform for workflow automation');
const classes = classification.suggested_classes.map(c => c.class_number); // [9, 42]

// Then check the brand name
const result = await checkBrandName('CloudFlow', classes);

Example Response

{
  "risk_level": "MEDIUM",
  "risk_score": 0.58,
  "conflicts_by_jurisdiction": {
    "US": {
      "conflict_count": 3,
      "highest_risk": 0.72,
      "conflicts": [
        {
          "mark": {
            "text": "CLOUDFLOW",
            "id": "tm_us_1234567"
          },
          "similarity_score": 0.98,
          "status": "live_registered",
          "classes": [42],
          "owner": "CloudFlow Technologies Inc.",
          "reason": "Exact match in Class 42 (SaaS services)"
        }
      ]
    },
    "EU": {
      "conflict_count": 1,
      "highest_risk": 0.45,
      "conflicts": []
    },
    "UK": {
      "conflict_count": 0,
      "highest_risk": 0.0,
      "conflicts": []
    }
  },
  "recommendation": "HIGH_RISK_IN_US",
  "analysis_time_ms": 542
}

Step 3: Display Risk Levels

Show clear visual indicators for each jurisdiction.
function getRiskIndicator(riskLevel) {
  const indicators = {
    'CLEAR': {
      color: 'green',
      icon: '✓',
      label: 'Available',
      description: 'No conflicts found',
      canProceed: true
    },
    'LOW': {
      color: 'blue',
      icon: 'i',
      label: 'Low Risk',
      description: 'Minor similarities exist',
      canProceed: true
    },
    'MEDIUM': {
      color: 'orange',
      icon: '⚠',
      label: 'Moderate Risk',
      description: 'Potential conflicts detected',
      canProceed: false
    },
    'HIGH': {
      color: 'red',
      icon: '✕',
      label: 'High Risk',
      description: 'Strong conflicts found',
      canProceed: false
    }
  };

  return indicators[riskLevel];
}

UI Component

function BrandNameChecker() {
  const [brandName, setBrandName] = useState('');
  const [businessDesc, setBusinessDesc] = useState('');
  const [result, setResult] = useState(null);
  const [checking, setChecking] = useState(false);

  async function validateName() {
    if (brandName.length < 2) return;

    setChecking(true);
    const checkResult = await checkBrandName(brandName, businessDesc);
    setResult(checkResult);
    setChecking(false);
  }

  const indicator = result ? getRiskIndicator(result.risk_level) : null;

  return (
    <div className="brand-checker">
      <h2>Check Brand Name Availability</h2>

      <input
        type="text"
        value={brandName}
        onChange={(e) => setBrandName(e.target.value)}
        onBlur={validateName}
        placeholder="Enter your brand name"
      />

      <textarea
        value={businessDesc}
        onChange={(e) => setBusinessDesc(e.target.value)}
        placeholder="Describe your business (e.g., SaaS platform for workflow automation)"
      />

      <button onClick={validateName} disabled={checking}>
        {checking ? 'Checking...' : 'Check Availability'}
      </button>

      {indicator && (
        <div className={`result result-${indicator.color}`}>
          <div className="risk-badge">
            <span className="icon">{indicator.icon}</span>
            <span className="label">{indicator.label}</span>
          </div>
          <p>{indicator.description}</p>
        </div>
      )}
    </div>
  );
}

Step 4: Multi-Jurisdiction Results

Display results for each jurisdiction separately.
function JurisdictionResults({ conflictsByJurisdiction }) {
  return (
    <div className="jurisdiction-results">
      <h3>Results by Jurisdiction</h3>

      {Object.entries(conflictsByJurisdiction).map(([code, data]) => {
        const jurisdictionNames = {
          'US': 'United States',
          'EU': 'European Union',
          'UK': 'United Kingdom'
        };

        const riskLevel = data.highest_risk > 0.7 ? 'HIGH' :
                         data.highest_risk > 0.5 ? 'MEDIUM' :
                         data.highest_risk > 0.3 ? 'LOW' : 'CLEAR';

        const indicator = getRiskIndicator(riskLevel);

        return (
          <div key={code} className={`jurisdiction-card ${indicator.color}`}>
            <div className="jurisdiction-header">
              <h4>{jurisdictionNames[code]}</h4>
              <span className={`badge badge-${indicator.color}`}>
                {indicator.icon} {indicator.label}
              </span>
            </div>

            <div className="stats">
              <span>{data.conflict_count} conflicts found</span>
              {data.conflict_count > 0 && (
                <span>Highest similarity: {(data.highest_risk * 100).toFixed(0)}%</span>
              )}
            </div>

            {data.conflicts.length > 0 && (
              <div className="conflicts">
                <h5>Top Conflicts:</h5>
                {data.conflicts.slice(0, 3).map(conflict => (
                  <div key={conflict.mark.id} className="conflict">
                    <strong>{conflict.mark.text}</strong>
                    <span className="similarity">
                      {(conflict.similarity_score * 100).toFixed(0)}% similar
                    </span>
                    <p className="reason">{conflict.reason}</p>
                    <small>Owner: {conflict.owner}</small>
                  </div>
                ))}
              </div>
            )}
          </div>
        );
      })}
    </div>
  );
}

Step 5: Deep Clearance Analysis

For names that pass the fast check, offer detailed analysis.
async function runDeepClearance(name, businessDesc) {
  const response = await fetch('https://api.signa.so/v1/analysis/clearance', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.TRADEMARK_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      trademark: name,
      business_description: businessDesc,
      offices: ['USPTO', 'EUIPO', 'UKIPO']
    })
  });

  return await response.json();
}

Deep Analysis UI

function DetailedAnalysis({ result }) {
  const [deepAnalysis, setDeepAnalysis] = useState(null);
  const [loading, setLoading] = useState(false);

  async function runAnalysis() {
    setLoading(true);
    const analysis = await runDeepClearance(
      result.brand_name,
      result.business_description
    );
    setDeepAnalysis(analysis);
    setLoading(false);
  }

  // Only show for CLEAR or LOW risk names
  if (result.risk_level === 'HIGH' || result.risk_level === 'MEDIUM') {
    return null;
  }

  return (
    <div className="deep-analysis">
      <h3>Get Detailed Clearance Report</h3>
      <p>Run a comprehensive AI analysis with detailed recommendations.</p>

      <button onClick={runAnalysis} disabled={loading}>
        {loading ? 'Analyzing...' : 'Run Deep Analysis (5 credits)'}
      </button>

      {deepAnalysis && (
        <div className="analysis-report">
          <div className="risk-assessment">
            <h4>Overall Risk Assessment</h4>
            <div className={`risk-badge risk-${deepAnalysis.risk_level.toLowerCase()}`}>
              {deepAnalysis.risk_level}
            </div>
            <p className="recommendation">{deepAnalysis.recommendation}</p>
          </div>

          <div className="suggested-classes">
            <h4>Relevant Trademark Classes</h4>
            {Object.entries(deepAnalysis.relevant_classes).map(([classNum, info]) => (
              <div key={classNum} className="class-item">
                <strong>Class {classNum}: {info.name}</strong>
                <p>{info.reason}</p>
                <span className="confidence">
                  Confidence: {(info.confidence * 100).toFixed(0)}%
                </span>
              </div>
            ))}
          </div>

          <div className="conflict-analysis">
            <h4>Detailed Conflict Analysis</h4>
            {deepAnalysis.conflicts.map(conflict => (
              <div key={conflict.mark_id} className="conflict-detail">
                <div className="conflict-header">
                  <h5>{conflict.mark_text}</h5>
                  <span className="risk-score">
                    Risk: {(conflict.risk_score * 100).toFixed(0)}%
                  </span>
                </div>
                <p className="conflict-reason">{conflict.conflict_reason}</p>
                <div className="conflict-meta">
                  <span>Owner: {conflict.owner}</span>
                  <span>Status: {conflict.status}</span>
                  <span>Classes: {conflict.classes.join(', ')}</span>
                </div>
              </div>
            ))}
          </div>

          <div className="next-steps">
            <h4>Next Steps</h4>
            <ul>
              {deepAnalysis.next_steps.map((step, i) => (
                <li key={i}>{step}</li>
              ))}
            </ul>
          </div>
        </div>
      )}
    </div>
  );
}

Displaying Class Suggestions to Users

Show users which trademark classes are relevant to their business.
function ClassSuggestions({ businessDesc }) {
  const [classes, setClasses] = useState(null);

  useEffect(() => {
    if (businessDesc.length > 10) {
      getClassSuggestions(businessDesc).then(setClasses);
    }
  }, [businessDesc]);

  if (!classes) return null;

  return (
    <div className="class-suggestions">
      <h4>Recommended Trademark Classes</h4>
      <p>Based on your business description, you should check these classes:</p>

      <div className="classes-list">
        {classes.suggested_classes.map(cls => (
          <div key={cls.class_number} className="class-card">
            <div className="class-number">Class {cls.class_number}</div>
            <div className="class-name">{cls.name}</div>
            <p className="class-reason">{cls.reason}</p>
            <div className="confidence-bar">
              <div
                className="confidence-fill"
                style={{ width: `${cls.confidence * 100}%` }}
              />
              <span>{(cls.confidence * 100).toFixed(0)}% match</span>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

Complete Example

Here’s a full working implementation:
class BrandNameValidator {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseUrl = 'https://api.signa.so/v1';
  }

  async checkAvailability(brandName, businessDescription, jurisdictions = ['US', 'EU', 'UK']) {
    // 1. First, classify the business to get relevant Nice classes
    const classification = await this.classify(businessDescription);
    const classes = classification.suggested_classes.map(c => c.class_number);

    // 2. Run fast conflict check with those classes
    const fastCheck = await this.fastCheck(brandName, classes, jurisdictions);

    // 3. Return results with class information
    return {
      brand_name: brandName,
      risk_level: fastCheck.risk_level,
      risk_score: fastCheck.risk_score,
      conflicts_by_jurisdiction: fastCheck.conflicts_by_jurisdiction,
      suggested_classes: classification.suggested_classes,
      recommendation: this.getRecommendation(fastCheck),
      can_proceed: fastCheck.risk_level === 'CLEAR' || fastCheck.risk_level === 'LOW'
    };
  }

  async classify(businessDescription) {
    const response = await fetch(`${this.baseUrl}/analysis/classify`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ text: businessDescription })
    });
    return response.json();
  }

  async fastCheck(text, classes, jurisdictions) {
    const response = await fetch(`${this.baseUrl}/analysis/check`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ text, classes, jurisdictions })
    });
    return response.json();
  }

  async deepClearance(trademark, businessDescription) {
    const response = await fetch(`${this.baseUrl}/analysis/clearance`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        trademark,
        business_description: businessDescription,
        offices: ['USPTO', 'EUIPO', 'UKIPO']
      })
    });
    return response.json();
  }

  getRecommendation(result) {
    const hasHighRiskJurisdiction = Object.values(result.conflicts_by_jurisdiction)
      .some(j => j.highest_risk > 0.7);

    if (hasHighRiskJurisdiction) {
      return 'HIGH_RISK - Choose a different name';
    }

    if (result.risk_level === 'MEDIUM') {
      return 'MODERATE_RISK - Consider alternatives or run deep analysis';
    }

    if (result.risk_level === 'LOW') {
      return 'LOW_RISK - Proceed with caution, review conflicts';
    }

    return 'CLEAR - Name appears available';
  }
}

// Usage
const validator = new BrandNameValidator(process.env.TRADEMARK_API_KEY);

const result = await validator.checkAvailability(
  'CloudFlow',
  'SaaS platform for workflow automation and team collaboration'
);

console.log(`Risk Level: ${result.risk_level}`);
console.log(`Recommendation: ${result.recommendation}`);
console.log(`Can proceed: ${result.can_proceed}`);

// If low risk, get detailed analysis
if (result.can_proceed) {
  const deepAnalysis = await validator.deepClearance(
    'CloudFlow',
    'SaaS platform for workflow automation and team collaboration'
  );
  console.log('Detailed analysis:', deepAnalysis);
}

Real-World Examples

Example 1: Available Name

// Input
{
  brandName: "Streamline",
  businessDescription: "Project management software for remote teams"
}

// Fast Check Result
{
  risk_level: "CLEAR",
  conflicts_by_jurisdiction: {
    "US": { conflict_count: 0 },
    "EU": { conflict_count: 0 },
    "UK": { conflict_count: 0 }
  },
  recommendation: "CLEAR - Name appears available"
}
// ✓ Safe to proceed

Example 2: Low Risk Name

// Input
{
  brandName: "SwiftTask",
  businessDescription: "Task management app for developers"
}

// Fast Check Result
{
  risk_level: "LOW",
  conflicts_by_jurisdiction: {
    "US": {
      conflict_count: 2,
      highest_risk: 0.42,
      conflicts: [
        {
          mark: "SWIFTTASKS",
          similarity_score: 0.42,
          reason: "Similar but different overall impression"
        }
      ]
    }
  },
  recommendation: "LOW_RISK - Proceed with caution"
}
// ⚠ Review conflicts but can proceed

Example 3: High Risk Name

// Input
{
  brandName: "Microsoft Flow",
  businessDescription: "Workflow automation platform"
}

// Fast Check Result
{
  risk_level: "HIGH",
  conflicts_by_jurisdiction: {
    "US": {
      conflict_count: 1,
      highest_risk: 0.98,
      conflicts: [
        {
          mark: "MICROSOFT POWER AUTOMATE (FLOW)",
          similarity_score: 0.98,
          owner: "Microsoft Corporation",
          status: "live_registered",
          reason: "Exact match with famous registered trademark"
        }
      ]
    }
  },
  recommendation: "HIGH_RISK - Choose a different name"
}
// ✗ Do not use

Best Practices

Validate on Blur

Don’t check on every keystroke - wait until user finishes typing:
<input
  value={brandName}
  onChange={(e) => setBrandName(e.target.value)}
  onBlur={() => validateName()}  // Check when user leaves field
/>

Cache Results

Cache checks for 24 hours to avoid redundant API calls:
const cache = new Map();

async function validateWithCache(name, desc) {
  const key = `${name.toLowerCase()}:${desc}`;

  if (cache.has(key)) {
    return cache.get(key);
  }

  const result = await checkBrandName(name, desc);
  cache.set(key, result);

  return result;
}

Progressive Disclosure

Show deep analysis only for promising names:
// Only offer deep analysis for CLEAR or LOW risk
if (result.risk_level === 'CLEAR' || result.risk_level === 'LOW') {
  showDeepAnalysisButton();
}

Cost Analysis

For a naming agency checking 50 names/month:
  • Classification (get Nice classes): 50 × 1 credit = 50 credits
  • Fast conflict checks: 50 × 2 credits = 100 credits
  • Deep analysis (10 promising names): 10 × 5 credits = 50 credits
  • Total: 200 credits/month
On the Starter plan (1,000 credits), an agency could validate 250+ brand names.

Next Steps

Support

Building a naming tool for a different use case? We’d love to help. Contact us at [email protected].