Skip to main content

Multi-Device Sync Guide

Periscope supports capturing browser context from multiple devices and browsers under a single Lovelace account. Your AI agents receive a unified stream of context regardless of which device you are browsing on.

Overview

When you install the Periscope extension on multiple browsers or devices, each one independently streams context to the Periscope service. The service identifies your devices, routes events to a unified channel, and makes the combined history available through the REST API and WebSocket.

This means you can start researching on your laptop, continue on your desktop, and your agent has the full browsing history from both.

Device Identification

Each Periscope extension instance reports a DeviceInfo object that identifies the source of context events:

typescript
interface DeviceInfo {
  /** Unique identifier for this device, generated on first install */
  id: string;
  /** User-friendly device name, e.g. "Chrome on MacBook Pro" */
  name: string;
  /** Operating system: "macOS", "Windows", "Linux", "ChromeOS" */
  os: string;
  /** Form factor: "desktop", "laptop", "tablet" */
  formFactor: string;
  /** CPU architecture: "arm64", "x86_64" */
  arch: string;
}

The id field is a UUID generated when the extension is first installed. It persists across browser restarts and extension updates, but is reset if the extension is uninstalled and reinstalled.

Viewing Your Devices

You can see all devices associated with your account via the REST API:

bash
curl -s -H "Authorization: Bearer $LOVELACE_API_TOKEN" \
  https://periscope.uselovelace.com/api/v1/context/current | jq '.device'

Or list all devices that have synced context in the last 30 days:

bash
curl -s -H "Authorization: Bearer $LOVELACE_API_TOKEN" \
  "https://periscope.uselovelace.com/api/v1/context/history?limit=100" | \
  jq '[.items[].device] | unique_by(.id)'

Naming Your Devices

Each extension auto-generates a device name from the browser and operating system (e.g., "Chrome on macOS"). You can customize this in the extension popup under Settings > Device > Device Name. Using distinct names makes it easier to filter context by device in your agent.

Setting Up Multiple Browsers

Same Machine, Multiple Browsers

To capture context from both Chrome and Firefox on the same machine:

  1. Install the Periscope extension in Chrome (see Extension Setup Guide)
  2. Install the Periscope extension in Firefox
  3. Sign in to the same Lovelace account in both extensions
  4. Each browser gets its own DeviceInfo.id but shares the same user channel

Both browsers stream context independently. Your agent receives events from both.

Multiple Machines

To capture context from your laptop and desktop:

  1. Install the Periscope extension on your laptop browser
  2. Install the Periscope extension on your desktop browser
  3. Sign in to the same Lovelace account on both
  4. Each machine gets its own DeviceInfo with distinct id, name, and os fields

Context from both machines appears in your unified history and is available through the same API token.

Channel Routing

All Periscope WebSocket events are routed based on your userId, not the device. This is the key design decision that makes multi-device sync work transparently.

How channelId Routing Works

When the extension sends a context event, the Periscope service:

  1. Authenticates the request using the extension's JWT token
  2. Extracts the userId from the token
  3. Routes the event to the user:{userId} channel
  4. All WebSocket connections subscribed to channels for that user receive the event
┌──────────────┐     ┌──────────────────┐     ┌─────────────────┐
│ Chrome on    │────▶│                  │────▶│                 │
│ MacBook      │     │  Periscope       │     │  Your Agent     │
└──────────────┘     │  Service         │     │  (WebSocket     │
                     │                  │     │   subscriber)   │
┌──────────────┐     │  Routes all to   │     │                 │
│ Firefox on   │────▶│  user:{userId}   │────▶│  Receives all   │
│ Desktop      │     │                  │     │  events         │
└──────────────┘     └──────────────────┘     └─────────────────┘

broadcastToUser Behavior

The internal broadcastToUser(userId, event) function delivers events to every active WebSocket connection for that user. This means:

  • An agent connected via WebSocket receives events from all your devices
  • Multiple agents connected simultaneously all receive the same events
  • There is no need to subscribe to device-specific channels

Subscribing in Your Agent

Your agent subscribes to the same channels regardless of how many devices you have:

typescript
import { PeriscopeClient } from "@lovelace-ai/periscope-client";

const client = new PeriscopeClient({
  baseUrl: "https://periscope.uselovelace.com",
  wsUrl: "wss://periscope.uselovelace.com/ws",
  token: process.env.LOVELACE_API_TOKEN,
});

await client.connect();

// This receives events from ALL your devices
client.subscribe("current-context", (context) => {
  console.log(`[${context.device.name}] ${context.url}`);
});

// Tab events from all devices
client.subscribe("tab-events", (event) => {
  console.log(`[${event.device.name}] Tab ${event.action}: ${event.tabId}`);
});

Filtering by Device

If your agent needs to focus on a specific device, filter by device.id in the event handler:

typescript
const TARGET_DEVICE_ID = "device_abc123";

client.subscribe("current-context", (context) => {
  if (context.device.id !== TARGET_DEVICE_ID) {
    return;
  }
  // Only process events from the target device
  updateAgentContext(context);
});

Conflict Resolution

When multiple devices stream context simultaneously, conflicts can occur. Periscope uses simple, predictable rules.

Current Context: Last-Write-Wins

The GET /current endpoint always returns the most recent context event across all devices. If you navigate on your laptop and then navigate on your desktop, GET /current returns the desktop's page.

Timeline:
  10:00:01  Laptop navigates to github.com
  10:00:03  GET /current → github.com (laptop)
  10:00:05  Desktop navigates to stackoverflow.com
  10:00:06  GET /current → stackoverflow.com (desktop)

This is intentional -- the "current context" represents what you are looking at right now, which is the most recently active device.

History: All Events Stored

The GET /history endpoint returns context events from all devices, ordered by timestamp. Nothing is lost -- even if two devices send events at nearly the same time, both are stored.

bash
curl -s -H "Authorization: Bearer $LOVELACE_API_TOKEN" \
  "https://periscope.uselovelace.com/api/v1/context/history?limit=10" | jq '.items[] | {url, device: .device.name, timestamp}'

Example output showing interleaved events from two devices:

json
[
  {
    "url": "https://github.com/pulls",
    "device": "Chrome on MacBook",
    "timestamp": "2026-03-02T10:00:01Z"
  },
  {
    "url": "https://stackoverflow.com/questions/123",
    "device": "Firefox on Desktop",
    "timestamp": "2026-03-02T10:00:05Z"
  },
  {
    "url": "https://github.com/issues/456",
    "device": "Chrome on MacBook",
    "timestamp": "2026-03-02T10:02:30Z"
  }
]

Search Across Devices

The GET /search endpoint searches across all devices by default. You can filter by device using the deviceId query parameter:

bash
# Search all devices
curl -s -H "Authorization: Bearer $LOVELACE_API_TOKEN" \
  "https://periscope.uselovelace.com/api/v1/context/search?q=react+hooks"

# Search only a specific device
curl -s -H "Authorization: Bearer $LOVELACE_API_TOKEN" \
  "https://periscope.uselovelace.com/api/v1/context/search?q=react+hooks&deviceId=device_abc123"

Practical Example: Cross-Device Research

Here is a common workflow that multi-device sync enables:

  1. Morning on your laptop: You research a bug by browsing Stack Overflow, GitHub issues, and documentation. Periscope captures 15 context events.

  2. Afternoon at your desk: You sit down at your desktop and ask your agent: "What was I reading about that React rendering bug this morning?"

  3. Agent queries history: The agent calls GET /search?q=react+rendering&since=2026-03-02T06:00:00Z and finds the relevant pages from your laptop session.

  4. Agent responds with context: "This morning you looked at three Stack Overflow posts about React re-rendering issues and a GitHub issue about useMemo not memoizing correctly. The most relevant seems to be the GitHub issue at github.com/facebook/react/issues/12345 where you selected text about the dependency array behavior."

The agent has full visibility into your browsing across both machines without any manual context transfer.

Troubleshooting

Events Not Appearing from Second Device

  1. Verify both extensions are signed into the same Lovelace account
  2. Check the extension popup on each device -- both should show "Connected"
  3. Verify the API token you are using has access to the correct user

Seeing Duplicate Events

Duplicate events can occur if the same browser has the extension installed twice (e.g., from Chrome Web Store and as an unpacked extension). Remove one installation.

Wrong Device Shown as "Current"

The GET /current endpoint returns the most recently active device. If your desktop shows as current but you are browsing on your laptop, the desktop may have sent a more recent event (e.g., a tab activation from a background tab). This is expected behavior.

High Event Volume from Multiple Devices

If your agent is receiving more events than it can process, consider:

  • Subscribing only to current-context instead of user-contexts (fewer events)
  • Filtering by context.kind to only process page.navigation and text.selection
  • Adding a debounce to your event handler to batch rapid navigation sequences