Skip to main content

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:

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:

bash
curl -X GET https://periscope.uselovelace.com/api/v1/context/current \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json"

Response:

json
{
  "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:

FieldDescription
contextIdUnique identifier for this context snapshot (branded ContextId type)
userIdThe authenticated user who generated this context
urlCurrent page URL from the active browser tab
titlePage title from the document's <title> tag
contentExtracted page content (text, HTML, or markdown depending on context type)
timestampISO 8601 timestamp of when the context was captured
privacyLevelOne 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:

bash
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.

typescript
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:

  1. Connect — establish WebSocket connection
  2. Welcome — server sends a welcome message with your connectionId
  3. Authenticate — client sends auth message with token and userId
  4. Subscribe — client subscribes to one or more channels
  5. Receive events — server pushes events on subscribed channels
  6. 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:

bash
# 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:

ParameterDescription
tabIdFilter by specific browser tab
typeContext type: page, selection, element, form, media, navigation, custom
privacyLevelFilter by privacy level
urlPatternURL substring or pattern match
startTime / endTimeTime range filter (ISO 8601)
limitMax results (1-1000, default 50)
offsetPagination offset

Step 6: Use the TypeScript SDK

For a more ergonomic experience, use the TypeScript SDK which wraps both the REST API and WebSocket:

bash
pnpm add @lovelace-ai/periscope-client
typescript
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:

StatusMeaningSolution
401Missing or invalid authentication tokenCheck your API key is valid and included in the Authorization header
404Context not found (no active context yet)The extension may not have synced yet — browse to a page and wait a moment
429Rate limit exceededCheck X-RateLimit-Reset header and retry after the specified time
207Partial success (batch sync)Some items succeeded, some failed — check individual results

Next Steps