Getting Started with Periscope
Install the extension and start consuming browser context in minutes
This guide walks you through installing the Periscope browser extension, making your first API call to retrieve browser context, and subscribing to real-time context updates via WebSocket.
Prerequisites
- A Lovelace account with an API key (get one here)
- Chrome, Edge, or Firefox browser
- Node.js 20+ (for the SDK examples)
Step 1: Install the Browser Extension
Install the Lovelace browser extension from your browser's extension store:
- Chrome/Edge: Chrome Web Store (search "Lovelace")
- Firefox: Firefox Add-ons (search "Lovelace")
Once installed, click the extension icon and sign in with your Lovelace account. The extension will begin capturing browser context automatically.
You can verify the extension is working by checking the extension popup — it should show a green "Connected" status and the URL of your current tab.
For detailed configuration including per-domain privacy rules and URL pattern filtering, see the Extension Setup Guide.
Step 2: Fetch Current Context
Make your first API call to retrieve the current browser context:
curl -X GET https://periscope.uselovelace.com/api/v1/context/current \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json"
Response:
{
"contextId": "ctx_abc123",
"userId": "user_456",
"url": "https://docs.example.com/guide",
"title": "Example Documentation Guide",
"content": "Page content extracted from the browser...",
"timestamp": "2026-03-02T12:00:00Z",
"privacyLevel": "public"
}
Understanding the response:
| Field | Description |
|---|---|
contextId | Unique identifier for this context snapshot (branded ContextId type) |
userId | The authenticated user who generated this context |
url | Current page URL from the active browser tab |
title | Page title from the document's <title> tag |
content | Extracted page content (text, HTML, or markdown depending on context type) |
timestamp | ISO 8601 timestamp of when the context was captured |
privacyLevel | One of public, private, restricted, or filtered — controls what data is shared. See Privacy Model |
If the response is empty or returns a 404, the extension may not be syncing yet. Check the extension popup for connection status, or wait a few seconds for the first sync to complete.
Step 3: Sync Context from the Extension
The extension automatically syncs context to the Periscope service. Under the hood, it sends a POST /api/v1/context/sync request with a SyncMessage:
curl -X POST https://periscope.uselovelace.com/api/v1/context/sync \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"id": "msg_001",
"type": "create",
"timestamp": "2026-03-02T12:00:00Z",
"userId": "user_456",
"extensionId": "ext_chrome_abc",
"payload": {
"type": "context",
"operation": "create",
"context": {
"id": "ctx_new123",
"type": "page",
"tabId": "tab_789",
"userId": "user_456",
"capturedAt": "2026-03-02T12:00:00Z",
"privacyLevel": "public",
"tabMetadata": {
"id": "tab_789",
"url": "https://docs.example.com/guide",
"title": "Example Guide",
"isActive": true,
"isLoading": false,
"windowId": 1,
"lastUpdated": "2026-03-02T12:00:00Z"
}
}
}
}'
You typically don't need to call this endpoint directly — the extension handles it. But understanding the sync message format is useful for building custom integrations or testing.
Step 4: Connect via WebSocket
For real-time context updates, connect to the WebSocket API. This is how agents typically consume context — they subscribe to a channel and receive updates as the user browses.
import { PeriscopeClient } from "@lovelace-ai/periscope-client";
const client = new PeriscopeClient({
token: "YOUR_API_KEY",
userId: "user_456",
});
await client.connect();
// Subscribe to current context updates
client.subscribe("current-context", (context) => {
console.log("Context updated:", context.url, context.title);
});
// Subscribe to all tab events
client.subscribe("tab-events", (event) => {
console.log("Tab event:", event.type, event.data);
});
The WebSocket connection lifecycle is:
- Connect — establish WebSocket connection
- Welcome — server sends a
welcomemessage with yourconnectionId - Authenticate — client sends
authmessage with token and userId - Subscribe — client subscribes to one or more channels
- Receive events — server pushes events on subscribed channels
- Heartbeat — client sends periodic heartbeats to stay alive (every 25-30 seconds)
See Real-Time Streaming for the full protocol specification.
Step 5: Search Context History
Query past browsing context with filters:
# Search by URL pattern
curl -X GET "https://periscope.uselovelace.com/api/v1/context/search?urlPattern=docs.example.com&limit=10" \
-H "Authorization: Bearer YOUR_API_KEY"
# Search by context type
curl -X GET "https://periscope.uselovelace.com/api/v1/context/search?type=selection&limit=5" \
-H "Authorization: Bearer YOUR_API_KEY"
# Search by time range
curl -X GET "https://periscope.uselovelace.com/api/v1/context/search?startTime=2026-03-01T00:00:00Z&endTime=2026-03-02T23:59:59Z" \
-H "Authorization: Bearer YOUR_API_KEY"
Available search filters:
| Parameter | Description |
|---|---|
tabId | Filter by specific browser tab |
type | Context type: page, selection, element, form, media, navigation, custom |
privacyLevel | Filter by privacy level |
urlPattern | URL substring or pattern match |
startTime / endTime | Time range filter (ISO 8601) |
limit | Max results (1-1000, default 50) |
offset | Pagination offset |
Step 6: Use the TypeScript SDK
For a more ergonomic experience, use the TypeScript SDK which wraps both the REST API and WebSocket:
pnpm add @lovelace-ai/periscope-client
import { PeriscopeClient } from "@lovelace-ai/periscope-client";
const client = new PeriscopeClient({
token: "YOUR_API_KEY",
userId: "user_456",
});
// REST: Get current context
const current = await client.getCurrentContext();
console.log(current.url, current.title);
// REST: Search history
const results = await client.searchContexts({
urlPattern: "github.com",
limit: 10,
});
for (const ctx of results) {
console.log(ctx.url, ctx.timestamp);
}
// REST: Get context history
const history = await client.getContextHistory({ limit: 20 });
// WebSocket: Stream real-time updates
await client.connect();
client.subscribe("current-context", (ctx) => {
console.log("Now viewing:", ctx.url);
});
client.subscribe("tab-events", (event) => {
console.log("Tab event:", event.type);
});
// Handle disconnections
client.on("disconnect", () => {
console.log("Disconnected, will auto-reconnect...");
});
client.on("error", (err) => {
console.error("Connection error:", err);
});
The SDK handles authentication, heartbeats, reconnection with exponential backoff, and type-safe event handling automatically.
Error Handling
Common error responses you may encounter:
| Status | Meaning | Solution |
|---|---|---|
401 | Missing or invalid authentication token | Check your API key is valid and included in the Authorization header |
404 | Context not found (no active context yet) | The extension may not have synced yet — browse to a page and wait a moment |
429 | Rate limit exceeded | Check X-RateLimit-Reset header and retry after the specified time |
207 | Partial success (batch sync) | Some items succeeded, some failed — check individual results |
Next Steps
- Browser Context Model — Understand the data model in depth
- Event System — Learn about the 10 event payload types
- Privacy Model — Configure privacy levels and filtering
- Agent Integration Guide — Build agents that consume browser context
- REST API Reference — Complete endpoint documentation
- WebSocket API Reference — Real-time streaming protocol
- Tutorials — Build complete applications with Periscope