Skip to content

Admin Overlay

The Spotlight admin overlay is a suite of in-context tools that appear directly on your application when an authenticated admin user loads the page with the SDK installed. Admins can build tours, select elements, customize themes, view analytics, and edit content -- all without leaving the host application.

How It Works

When the SDK initializes, it performs a two-phase authentication check:

  1. API key validation -- the X-API-Key header identifies the tenant.
  2. JWT validation -- the Authorization: Bearer token is verified against the tenant's JWKS endpoint.

If the authenticated user is detected as an admin (via the tenant's configured admin strategy), the SDK injects the admin overlay toolbar into the page.

ts
// The SDK automatically detects admin status after initialization
SpotlightSDK.init({
  apiKey: 'sk_live_...',
  // JWT is read from your existing auth system
  getToken: () => authService.getAccessToken(),
});
// If the user has admin privileges, the toolbar appears automatically.

Overlay Components

The admin overlay consists of five primary panels, each accessible from the floating toolbar:

ComponentPurposeShortcut
Tour BuilderCreate and edit guided product toursCtrl+Shift+T
Element SelectorTarget DOM elements with confidence scoringCtrl+Shift+E
Theme BuilderCustomize colors, typography, and spacingCtrl+Shift+H
Analytics PanelView completion rates and drop-off analysisCtrl+Shift+A
Inline EditorEdit content titles, bodies, and CTAs in placeCtrl+Shift+I

Admin Detection

Admin status is determined by a pluggable strategy configured per tenant. The backend supports three strategies:

python
# Checks the Spotlight.Admin.Users DynamoDB table
# An entry with matching tenant_id + user_id = admin
strategy = TableLookupStrategy(client=dynamodb_client, settings=settings)
is_admin = await strategy.is_admin(tenant_id, user_id, jwt_claims)
python
# Checks the JWT `permissions` array for a specific scope
# Works with Auth0 RBAC. Default scope: "spotlight:admin"
strategy = JwtPermissionStrategy(permission="spotlight:admin")
is_admin = await strategy.is_admin(tenant_id, user_id, jwt_claims)
python
# Checks a custom JWT claim for an admin role value
# Supports both string claims ("role": "admin")
# and array claims ("roles": ["admin", "user"])
strategy = JwtRoleStrategy(claim_name="role", admin_value="admin")
is_admin = await strategy.is_admin(tenant_id, user_id, jwt_claims)

Strategies can also be composed. The CompositeStrategy chains multiple strategies and returns True on the first match:

python
strategy = CompositeStrategy([
    JwtPermissionStrategy(),
    TableLookupStrategy(client, settings),
])

Architecture

Host Application
+-----------------------------------------------------+
|                                                     |
|   Your App UI                                       |
|                                                     |
|   +-----------------------------------------------+ |
|   | Spotlight Admin Overlay (injected by SDK)     | |
|   |                                               | |
|   |  [Toolbar]  [Tour Builder]  [Theme Builder]   | |
|   |  [Element Selector]  [Analytics]  [Editor]    | |
|   +-----------------------------------------------+ |
|                                                     |
+-----------------------------------------------------+
        |                       |
        | SDK API calls         | Admin API calls
        v                       v
   GET /v1/sdk/config      POST /v1/admin/tours
   POST /v1/sdk/events     PUT /v1/admin/themes
   POST /v1/sdk/progress   GET /v1/admin/analytics

The overlay communicates with two API surfaces:

  • SDK endpoints (/v1/sdk/*) -- for fetching configuration and recording user events.
  • Admin endpoints (/v1/admin/*) -- for CRUD operations on tours, content, themes, audiences, and admin users. These endpoints require the require_admin dependency, which runs the tenant's admin detection strategy.

Audit Trail

Every admin action emits a domain event that is persisted to the Spotlight.Audit.AdminActions DynamoDB table via EventBridge. Events include before/after snapshots of the modified entity:

json
{
  "event_type": "TourUpdatedByAdmin",
  "category": "admin",
  "tenant_id": "tenant_abc",
  "source": "admin_api",
  "data": {
    "actor_id": "user_123",
    "actor_email": "admin@example.com",
    "entity_type": "tour",
    "entity_id": "tour_456",
    "operation": "update",
    "before": { "title": "Old Title", "status": "draft" },
    "after": { "title": "New Title", "status": "draft" }
  }
}

The audit table supports querying by actor (gsi-actor) and by entity (gsi-entity) for full change history.

Permissions Summary

ActionRequires AdminAudit Logged
View tour analyticsYesNo
Create / edit toursYesYes
Publish / archive toursYesYes
Create / edit contentYesYes
Manage themesYesYes
Manage admin usersYesYes
Toggle circuit breakersYesYes
View SDK configNoNo
Record user eventsNoNo

Spotlight