> ## Documentation Index
> Fetch the complete documentation index at: https://docs.streampixel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Project User Stats

> Get a live snapshot of how many users are actively streaming and how many are waiting in queue for a project.

Return real-time counts of **live users** (active streaming sessions) and **queued users** (waiting for a worker) for a single project. Use this to power live status indicators, capacity dashboards, and autoscaling triggers without pulling the full session list.

<Info>
  Live and queue state is read from Redis, so this endpoint is fast enough to poll on a short interval. A few seconds between polls is plenty — the counts update in near real time.
</Info>

## Typical workflow

<Steps>
  <Step title="Authenticate">
    Pass `userId` and `apikey` as query parameters. Both are required.
  </Step>

  <Step title="Request the counts">
    Call `GET /projects/userStats/{projectId}` for the project you want to inspect.
  </Step>

  <Step title="Render or react">
    Use `liveUser` and `queueUser` in your dashboard, or compare against thresholds to trigger alerts.
  </Step>
</Steps>

## Prerequisites

| Requirement | Where to get it                                                                |
| ----------- | ------------------------------------------------------------------------------ |
| User ID     | [Finding your IDs](/resources/api-reference/finding-your-user-and-project-ids) |
| Project ID  | [Finding your IDs](/resources/api-reference/finding-your-user-and-project-ids) |
| API Key     | [API authentication](/resources/api-reference/api-authentication)              |

<Warning>
  Unlike most Streampixel endpoints (which take `apiKey` in the JSON body), this is a `GET` request — the API key is passed as the `apikey` query parameter. Treat the URL as sensitive: prefer server-side calls and avoid logging it in plain text.
</Warning>

## Path parameters

<ParamField path="projectId" type="string" required>
  The ID of the project to fetch live and queue user counts for.
</ParamField>

## Query parameters

<ParamField query="userId" type="string" required>
  The ID of the account that owns the project. Must match the project's owner.
</ParamField>

<ParamField query="apikey" type="string" required>
  Your Streampixel API key. Note the all-lowercase casing — this parameter is `apikey`, not `apiKey`.
</ParamField>

## Response

<ResponseField name="liveUser" type="number">
  Number of users currently in an active streaming session for this project. Sessions in `Terminated` or `Terminating` state are excluded.
</ResponseField>

<ResponseField name="queueUser" type="number">
  Number of users waiting in the project's queue for a worker to become available.
</ResponseField>

<RequestExample>
  ```bash cURL theme={"dark"}
  curl "https://api.streampixel.io/pixelStripeApi/projects/userStats/[PROJECT_ID]?userId=[YOUR_USER_ID]&apikey=[YOUR_API_KEY]"
  ```

  ```javascript Node.js theme={"dark"}
  const axios = require('axios');

  const { data } = await axios.get(
    `https://api.streampixel.io/pixelStripeApi/projects/userStats/${projectId}`,
    {
      params: {
        userId: '[YOUR_USER_ID]',
        apikey: '[YOUR_API_KEY]',
      },
    }
  );

  console.log(`Live: ${data.liveUser}, Queue: ${data.queueUser}`);
  ```

  ```python Python theme={"dark"}
  import requests

  response = requests.get(
      f"https://api.streampixel.io/pixelStripeApi/projects/userStats/{project_id}",
      params={
          "userId": "[YOUR_USER_ID]",
          "apikey": "[YOUR_API_KEY]",
      },
  )

  print(response.json())
  ```

  ```go Go theme={"dark"}
  package main

  import (
    "fmt"
    "io"
    "net/http"
    "net/url"
  )

  func main() {
    projectID := "[PROJECT_ID]"
    base := "https://api.streampixel.io/pixelStripeApi/projects/userStats/" + projectID

    q := url.Values{}
    q.Set("userId", "[YOUR_USER_ID]")
    q.Set("apikey", "[YOUR_API_KEY]")

    resp, err := http.Get(base + "?" + q.Encode())
    if err != nil {
      fmt.Println("Request failed:", err)
      return
    }
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)
    fmt.Println("Response:", string(body))
  }
  ```

  ```java Java theme={"dark"}
  import okhttp3.*;

  public class ProjectUserStats {
      public static void main(String[] args) throws Exception {
          OkHttpClient client = new OkHttpClient();

          HttpUrl url = HttpUrl.parse("https://api.streampixel.io/pixelStripeApi/projects/userStats/[PROJECT_ID]")
              .newBuilder()
              .addQueryParameter("userId", "[YOUR_USER_ID]")
              .addQueryParameter("apikey", "[YOUR_API_KEY]")
              .build();

          Request request = new Request.Builder().url(url).get().build();

          Response response = client.newCall(request).execute();
          System.out.println(response.body().string());
      }
  }
  ```
</RequestExample>

<ResponseExample>
  ```json 200 OK theme={"dark"}
  {
    "liveUser": 7,
    "queueUser": 2
  }
  ```

  ```json 400 Bad Request theme={"dark"}
  {
    "message": "projectId, userId and apikey are required"
  }
  ```

  ```json 401 Unauthorized theme={"dark"}
  {
    "message": "Invalid User"
  }
  ```

  ```json 401 Unauthorized theme={"dark"}
  {
    "message": "Unauthorized: Invalid API Key"
  }
  ```

  ```json 403 Forbidden theme={"dark"}
  {
    "message": "Access denied"
  }
  ```

  ```json 404 Not Found theme={"dark"}
  {
    "message": "Project not found"
  }
  ```

  ```json 500 Internal Server Error theme={"dark"}
  {
    "message": "Internal server error"
  }
  ```
</ResponseExample>

## Error reference

| Status | Message                                     | Cause                                                       |
| ------ | ------------------------------------------- | ----------------------------------------------------------- |
| `400`  | `projectId, userId and apikey are required` | One or more required parameters were omitted.               |
| `401`  | `Invalid User`                              | The supplied `userId` doesn't match any account.            |
| `401`  | `Unauthorized: Invalid API Key`             | The `apikey` doesn't match the user's current key.          |
| `403`  | `Access denied`                             | The project exists but isn't owned by `userId`.             |
| `404`  | `Project not found`                         | No project with the supplied `projectId`.                   |
| `500`  | `Internal server error`                     | Unexpected failure. Retry; if it persists, contact support. |

## Polling pattern

For a live dashboard, poll on a short interval and stop the timer when the page is hidden. This keeps the UI responsive without hammering the API.

```javascript Node.js / Browser theme={"dark"}
async function fetchStats(projectId, userId, apikey) {
  const url = new URL(
    `https://api.streampixel.io/pixelStripeApi/projects/userStats/${projectId}`
  );
  url.searchParams.set('userId', userId);
  url.searchParams.set('apikey', apikey);

  const res = await fetch(url);
  if (!res.ok) throw new Error(`stats failed: ${res.status}`);
  return res.json();
}

let timer = setInterval(async () => {
  try {
    const { liveUser, queueUser } = await fetchStats(
      '[PROJECT_ID]',
      '[YOUR_USER_ID]',
      '[YOUR_API_KEY]'
    );
    render({ liveUser, queueUser });
  } catch (err) {
    console.error(err);
  }
}, 5000);
```

<Tip>
  If you only need an aggregate view across many projects, batch your polling on the server and push updates to clients over WebSocket or SSE — this is far cheaper than every browser tab polling directly.
</Tip>

## Next

<CardGroup cols={2}>
  <Card title="List projects" icon="list" href="/resources/api-reference/list-projects">
    Enumerate every project so you can fetch stats for each.
  </Card>

  <Card title="Rate limits & errors" icon="gauge" href="/resources/api-reference/rate-limits-and-errors">
    Limits per endpoint and the standard error response format.
  </Card>
</CardGroup>
