---
title: Stream agent instance updates
description: A step-by-step walkthrough with a runnable example script —
  subscribe to an agent instance over the WebSocket API and print every change
  as it happens.
editUrl: true
head: []
template: doc
sidebar:
  hidden: false
  attrs: {}
pagefind: true
draft: false
---

When you want to watch a run as it happens — waiting out a smoke test, or feeding live status into your own tooling — polling the [HTTP API](/api/http) works, but a subscription is cheaper and faster. By the end of this page, you have a script that prints every change to one [instance](/platform/concepts/instance) until you stop it.

The subscription lives on the WebSocket API. [WebSocket API](/api/websocket) covers the connection and message format in full; this page is the shortest path to a working stream.

## Before you start

- An [API token](/platform/concepts/api-token) for the account the instance belongs to. Create one from the [Account › API tokens tab](/admin-ui/account/api-tokens).
- The ID of the agent instance you want to watch. Find it on the [Agent page › Instances tab](/admin-ui/agent/instances).
- Node.js with the `ws` package installed (`npm install ws`). The browser `WebSocket` API cannot set the `Authorization` header, so the example runs in Node.

## Steps

1. Save this script as `stream-instance.mjs`:

   ```javascript
   import WebSocket from "ws";

   const token = process.env.PREFACTOR_API_TOKEN;
   const instanceId = process.env.PREFACTOR_AGENT_INSTANCE_ID;

   if (!token || !instanceId) {
     console.error("Set PREFACTOR_API_TOKEN and PREFACTOR_AGENT_INSTANCE_ID");
     process.exit(1);
   }

   function connect() {
     const ws = new WebSocket("wss://app.prefactorai.com/api/v1/ws", {
       headers: { Authorization: `Bearer ${token}` },
     });

     ws.on("open", () => {
       ws.send(
         JSON.stringify({
           jsonrpc: "2.0",
           id: 1,
           method: "agent_instances/subscribe",
           params: { agent_instance_id: instanceId },
         }),
       );
     });

     ws.on("message", (data) => {
       const message = JSON.parse(data.toString());

       if (message.id !== undefined) {
         if (message.error) {
           console.error("Subscribe failed:", JSON.stringify(message.error));
           ws.close();
         } else {
           console.log(`Subscribed to ${instanceId}`);
         }
         return;
       }

       if (message.method === "error") {
         console.error("Prefactor is closing the stream:", message.params.message);
         return;
       }

       console.log(message.method, JSON.stringify(message.params));
     });

     ws.on("close", (code) => {
       if (code === 1008) {
         console.error("Authentication is no longer valid - check the API token.");
         process.exit(1);
       }
       console.log(`Connection closed (${code}); reconnecting in 5s`);
       setTimeout(connect, 5000);
     });

     ws.on("error", (err) => {
       console.error("Connection error:", err.message);
     });
   }

   connect();
   ```

   The script does four things: opens the socket with the token in the `Authorization` header, sends `agent_instances/subscribe` once the socket is open, prints each notification that arrives, and reconnects when the connection closes — unless the close means your token stopped being valid.

2. Run it with your token and instance ID:

   ```bash
   PREFACTOR_API_TOKEN=your-token PREFACTOR_AGENT_INSTANCE_ID=your-instance-id node stream-instance.mjs
   ```

   You should see `Subscribed to your-instance-id` within a second or two. The script now waits; every change to the instance prints as an `agent_instances/updated` line with the full instance details.

## Verify

With the script running, make the instance change — let the agent finish its run, or terminate the instance from the [Agent instance page](/admin-ui/agent-instance). A notification prints each time. If the instance is deleted, you get one `agent_instances/deleted` message and then nothing further.

## If it didn't work

- **`Connection error: Unexpected server response: 401`.** The token is missing, malformed, or no longer valid. Create a fresh one from the [Account › API tokens tab](/admin-ui/account/api-tokens).
- **`Subscribe failed` with code `-32602`.** The instance ID is wrong, or the token's account cannot see that instance. Check the ID on the [Agent page › Instances tab](/admin-ui/agent/instances).
- **`Subscribe failed` with code `-32000`.** You are rate limited. The error's `retry_after_ms` says how long to wait; [Rate limits](/api/rate-limits) covers how limits are applied.
- **The script exits after `Prefactor is closing the stream`.** The token was revoked, suspended, or expired mid-stream, and Prefactor closed the connection with code `1008`. Re-authenticate with a valid token.
- **`Subscribed to ...` prints, but no notifications arrive.** Notifications only fire when the instance changes. Record a span or let the run finish; if it stays silent, check that you subscribed to the right instance ID.

## Related

- [WebSocket API](/api/websocket) — the full protocol: methods, notifications, error codes, and close codes.
- [Rate limits](/api/rate-limits) — how limits are applied to socket calls.
- [Instance](/platform/concepts/instance) — the lifecycle you are watching.
- [Handle instance termination](/sdks/handling-termination) — how your agent finds out when Prefactor stops a run.