Element Selector
The element selector is the admin overlay tool that lets you target specific DOM elements on the host page for tours, tooltips, spotlights, and other content. It provides visual feedback about targeting reliability through a confidence scoring system.
Targeting Methods
Spotlight supports three methods for identifying DOM elements, evaluated in priority order:
| Priority | Method | Selector Format | Stability |
|---|---|---|---|
| 1 | data-spotlight attribute | [data-spotlight="dashboard-chart"] | Highest |
| 2 | Element ID | #user-profile-btn | High |
| 3 | CSS selector | .sidebar > nav > ul > li:nth-child(3) | Variable |
The ElementTarget value object enforces that at least one method is provided:
class ElementTarget(BaseModel):
"""Identifies a DOM element on the host page.
At least one targeting method must be provided.
Priority: data_attribute > element_id > css_selector.
"""
data_attribute: str | None = None # e.g. "dashboard-chart"
element_id: str | None = None # e.g. "user-profile-btn"
css_selector: str | None = None # e.g. ".sidebar > nav > li:nth-child(3)"
description: str | None = None # Human-readable labelThe best_selector property returns the highest-priority selector available:
target = ElementTarget(data_attribute="dashboard-chart", element_id="chart-1")
target.best_selector
# => '[data-spotlight="dashboard-chart"]'
target = ElementTarget(element_id="chart-1")
target.best_selector
# => '#chart-1'Using data-spotlight Attributes
The recommended approach is to add data-spotlight attributes to your application's HTML. These are stable across refactors since they are decoupled from structure and styling:
<!-- Recommended: explicit data-spotlight attributes -->
<button data-spotlight="create-project">New Project</button>
<div data-spotlight="dashboard-chart" id="revenue-chart">
<!-- chart content -->
</div>
<nav data-spotlight="main-navigation">
<ul>
<li><a href="/dashboard">Dashboard</a></li>
<li><a href="/projects">Projects</a></li>
</ul>
</nav>Benefits of data-spotlight:
- Survives CSS class renames and structural refactors.
- Communicates intent -- developers know which elements are targeted.
- No collision with existing IDs or test attributes.
- Can be scoped per feature:
data-spotlight="onboarding.step-1".
Confidence Levels
When an admin selects an element in the overlay, the SDK evaluates targeting reliability and assigns a confidence level:
Green -- High Confidence
The element has a data-spotlight attribute or a stable id. These selectors will reliably resolve across page loads and deployments.
Target: [data-spotlight="create-project"]
Confidence: GREEN
Reason: Explicit data-spotlight attribute foundYellow -- Medium Confidence
The element is identified by a CSS selector that is reasonably specific but depends on DOM structure. May break if the page layout changes.
Target: #app-container > .main-content > button.primary
Confidence: YELLOW
Reason: Structural CSS selector (3 levels deep)Red -- Low Confidence
The element relies on fragile selectors such as deeply nested positional paths, auto-generated class names, or selectors that match multiple elements.
Target: div > div > div:nth-child(2) > span:nth-child(4)
Confidence: RED
Reason: Deeply nested positional selector (5+ levels)Selector Health Monitoring
The backend tracks target_not_found events when the SDK cannot locate an element at runtime. The SelectorHealthService aggregates these failures into reports accessible from the admin panel:
report = await selector_health_service.get_health_report(
tenant_id="tenant_abc",
window_days=7,
failure_threshold=3, # only report selectors that failed 3+ times
)
# SelectorHealthReport(
# tenant_id="tenant_abc",
# total_failures=47,
# unique_selectors=5,
# broken_selectors=[
# SelectorFailure(content_id="tour_123", failure_count=22, ...),
# SelectorFailure(content_id="cnt_abc", failure_count=15, ...),
# ...
# ],
# analysis_window_days=7,
# )The admin API exposes this at GET /v1/admin/analytics/selector-health:
curl -H "X-API-Key: sk_live_..." \
-H "Authorization: Bearer <jwt>" \
https://api.example.com/v1/admin/analytics/selector-health?window_days=7{
"tenant_id": "tenant_abc",
"total_failures": 47,
"unique_selectors": 5,
"broken_selectors": [
{
"content_id": "tour_123",
"content_type": "tour",
"step_id": "step_3",
"failure_count": 22,
"url_path": "/dashboard",
"last_failure_at": "2025-05-10T14:22:00Z"
}
],
"analysis_window_days": 7
}The response is returned bare (no
{"data": ...}envelope) on this endpoint. All other admin endpoints follow the envelope convention.
Interactive Selection Mode
When an admin activates the element selector from the toolbar (Ctrl+Shift+E), the overlay enters interactive selection mode:
- Hover highlight -- as the cursor moves, hovering elements are outlined with a dashed border.
- Click to select -- clicking an element captures its targeting information.
- Selector evaluation -- the SDK examines the element for
data-spotlight,id, and generates a CSS selector fallback. - Confidence display -- a badge shows the green/yellow/red confidence level.
- Refinement -- the admin can manually edit or override the generated selector.
- Test -- a "Test Selector" button runs
document.querySelector()to verify the selector resolves to the intended element.
Best Practices
Add data-spotlight during development
The most reliable approach is to add data-spotlight attributes to key UI elements as part of your development workflow. Treat them like data-testid attributes -- stable anchors that are part of your application's contract.
Avoid auto-generated class names
CSS-in-JS libraries (Emotion, styled-components) and CSS Modules generate hashed class names that change between builds. Never use these as selectors.
Use the selector health dashboard
Review the selector health report weekly. A spike in target_not_found events after a deployment usually indicates a selector that needs updating.
Selector Priority Checklist
- Does the element have a
data-spotlightattribute? Use it. - Does the element have a stable, human-authored
id? Use it. - Is there a short, semantic CSS selector (e.g.,
nav.primary > .logo)? Acceptable, but monitor health. - Would you need a path with 4+ structural levels? Add a
data-spotlightattribute instead.