How Target Detection Works for Identifying Tracked Domains in Open-SEO
The detectTarget function uses a deterministic four-step heuristic—trimming whitespace, checking for dots without spaces, normalizing via the URL constructor, and validating hostnames—to classify user input as either a tracked domain or a brand keyword.
Open-SEO, an open-source SEO analytics platform, relies on precise input classification to separate domain-based tracking from keyword-based tracking. The target detection system serves as the gatekeeper for the "Add tracked domain" feature, ensuring only valid hostnames enter the rank-tracking pipeline while routing free-text brand queries to the appropriate keyword analysis workflows.
The Target Detection Algorithm
The detection logic resides in src/shared/targetDetection.ts and follows a strict, side-effect-free process that prioritizes speed and reliability.
Step 1: Input Sanitization
First, the raw input undergoes rawInput.trim() to eliminate leading and trailing whitespace, preventing accidental spaces from breaking domain validation.
Step 2: Quick Domain Heuristic
The algorithm performs a rapid preliminary check: the trimmed string must contain no spaces and must include a dot (.). This filters out obvious brand keywords like "Acme Widgets" before expensive parsing operations begin.
Step 3: Domain Normalization and Validation
If the heuristic passes, the system invokes normalizeDomain from src/types/schemas/domain.ts. This helper:
- Adds a dummy protocol if missing to satisfy the
URLconstructor - Extracts the hostname using the browser-compatible
URLAPI - Strips leading
www.prefixes - Returns the lower-cased hostname
If this normalization throws an error (invalid URL structure) or the resulting hostname lacks a dot, the input is rejected as a domain and classified as a keyword instead.
Step 4: Type Classification
Finally, detectTarget returns a discriminated union:
- For valid domains:
{ type: "domain", value: hostname } - For all other inputs:
{ type: "keyword", value: trimmed }
Domain Validation in the Rank-Tracking Pipeline
This detection mechanism is critical for the tracked domains feature, where each stored domain associates with specific location and city settings. When users enter competitors for AI-driven searches or add new properties to monitor, the application calls detectTarget before any external API requests (such as DataForSEO).
This architecture provides:
- Consistent input handling across client components like
src/client/features/ai-search/BrandLookupPage.tsxand server services such assrc/server/features/ai-search/services/brandLookup.ts - Early validation that prevents malformed URLs from consuming third-party API credits
- Clear separation between domain-based rank tracking and keyword-based share-of-voice analysis
Practical Implementation Examples
The detectTarget function handles various input formats uniformly:
import { detectTarget } from '@/shared/targetDetection';
// Valid domain without protocol
console.log(detectTarget('example.com'));
// → { type: 'domain', value: 'example.com' }
// Domain with protocol, www, and path
console.log(detectTarget('https://www.Example.com/page'));
// → { type: 'domain', value: 'example.com' }
// Brand keyword with spaces
console.log(detectTarget('Acme Widgets'));
// → { type: 'keyword', value: 'Acme Widgets' }
// Malformed input fails normalization
console.log(detectTarget('not a real domain.'));
// → { type: 'keyword', value: 'not a real domain.' }
These patterns are validated in the comprehensive test suite located at src/shared/targetDetection.test.ts.
Key Source Files
Understanding the target detection flow requires familiarity with these specific modules:
src/shared/targetDetection.ts– Core detection logic implementing the four-step classification algorithmsrc/shared/targetDetection.test.ts– Unit tests covering edge cases including internationalized domain names and protocol variationssrc/types/schemas/domain.ts– Contains thenormalizeDomainhelper responsible for hostname extraction andwww.strippingsrc/server/features/ai-search/services/brandLookup.ts– Server-side service demonstrating how detection results route domain entries to competitor analysissrc/client/features/ai-search/BrandLookupPage.tsx– React component utilizingdetectTargetfor real-time input validation in the user interface
Summary
- Target detection in Open-SEO relies on the
detectTargethelper to classify user input as either a domain or keyword before processing. - The algorithm uses a deterministic heuristic: no spaces, contains a dot, and successfully parses through
normalizeDomainusing the standardURLconstructor. - Valid domains return with type
"domain"and a cleaned hostname; all other inputs receive type"keyword". - This pure function operates safely in both server-side API handlers and client-side React components, ensuring consistent behavior across the stack.
- Early validation prevents invalid URLs from reaching external SEO data providers like DataForSEO.
Frequently Asked Questions
How does target detection handle URLs containing paths or query parameters?
The normalizeDomain function in src/types/schemas/domain.ts utilizes the browser-compatible URL constructor to extract only the hostname component, automatically discarding paths, query strings, and hash fragments. For example, https://example.com/blog/post resolves to example.com.
Does the system treat subdomains differently from root domains?
The detection algorithm preserves subdomains during normalization, only stripping the specific www. prefix. Inputs like blog.example.com return as type "domain" with value blog.example.com, maintaining distinct tracking for subdomain-specific SEO strategies.
Can detectTarget be safely called from server-side Node.js environments?
Yes, the function is deliberately pure and side-effect-free, making it safe for server-side services like brandLookup.ts. It relies only on standard JavaScript APIs (String methods and the global URL constructor) available in both Node.js and browser runtimes.
What happens when a user enters an invalid domain-like string?
If the input passes the initial heuristic (contains a dot, no spaces) but fails normalizeDomain validation—such as not a real domain.—the function catches the thrown error and returns { type: "keyword", value: "not a real domain." }, routing the input to keyword tracking instead of domain tracking.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →