useActiveConnections() · Nuxt Skew Protection · Nuxt SEO

-
-
-
-

[Sign In](https://nuxtseo.com/auth/github)

[Nuxt SEO on GitHub](https://github.com/harlan-zw/nuxt-seo)

Skew Protection

-
-
-
-
-
-
-
-
-
-

Search…```k`` /`

v1.1.1

- [Discord Support](https://discord.com/invite/275MBUBvgP)

### Nuxt API

-
-
-
-
-

### Nitro API

-
-

Nuxt API

# useActiveConnections()

[Copy for LLMs](https://nuxtseo.com/docs/skew-protection/api/use-active-connections.md)

A composable for accessing real-time statistics about active SSE/WebSocket connections and their version distribution.

This composable requires `connectionTracking: true` in your module config and only works with `sse` or `ws` update strategies. It does not support Pusher/Ably adapters.

Stats are not exposed to all users by default. You must implement the `skew:authorize-stats` hook to authorize specific connections.

## [Setup](#setup)

Enable connection tracking in your Nuxt config:

nuxt.config.ts

```
export default defineNuxtConfig({
  skewProtection: {
    connectionTracking: true,
    routeTracking: true, // optional: track current routes
    ipTracking: true, // optional: track IP addresses
  }
})
```

### [Authorization Hook](#authorization-hook)

The server only sends stats to authorized connections. Implement the `skew:authorize-stats` hook in a server plugin:

server/plugins/skew-auth.ts

```
export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('skew:authorize-stats', async ({ event, authorize }) => {
    // With nuxt-auth-utils
    const session = await getUserSession(event)
    if (session.user?.role === 'admin') {
      authorize()
    }
  })
})
```

## [Usage](#usage)

```
const { total, versions, routes, connections, yourId, authorized } = useActiveConnections()
```

## [Returns](#returns)

### [`total`](#total)

- Type: `ComputedRef<number>`

The total number of active connections across all versions.

```
const { total } = useActiveConnections()

console.log(total.value) // 42
```

### [`versions`](#versions)

- Type: `ComputedRef<Record<string, number>>`

A map of build IDs to connection counts, showing how many users are on each version.

```
const { versions } = useActiveConnections()

console.log(versions.value)
// { "abc123": 35, "def456": 7 }
```

### [`routes`](#routes)

- Type: `ComputedRef<Record<string, number>>`

A map of route paths to connection counts. Requires `routeTracking: true` in config.

```
const { routes } = useActiveConnections()

console.log(routes.value)
// { "/": 20, "/products": 15, "/checkout": 7 }
```

### [`connections`](#connections)

- Type: `ComputedRef<ConnectionInfo[]>`

Individual connection details including ID, version, route, and IP (when `ipTracking: true`).

```
const { connections } = useActiveConnections()

console.log(connections.value)
// [{ id: "abc123", version: "def456", route: "/", ip: "192.168.1.1" }]
```

### [`yourId`](#yourid)

- Type: `ComputedRef<string | undefined>`

Your connection ID to identify yourself in the connections list.

```
const { connections, yourId } = useActiveConnections()

const isMe = conn => conn.id === yourId.value
```

### [`authorized`](#authorized)

- Type: `ComputedRef<boolean | null>`

Whether the current connection is authorized to receive stats. Returns `null` while pending, `false` if denied, `true` if authorized.

```
const { authorized, total } = useActiveConnections()

// total.value will be 0 until authorized becomes true
```

## [Type Definitions](#type-definitions)

```
interface ConnectionInfo {
  id: string
  version: string
  route: string
  ip?: string // requires ipTracking: true
}

interface ConnectionStats {
  total: number
  versions: Record<string, number>
  routes: Record<string, number>
  connections: ConnectionInfo[]
  yourId?: string
}
```

## [Examples](#examples)

### [Admin Dashboard Widget](#admin-dashboard-widget)

```
<script setup lang="ts">
const { total, versions, routes, authorized } = useActiveConnections()

const versionList = computed(() => {
  return Object.entries(versions.value)
    .sort(([, a], [, b]) => b - a)
    .map(([id, count]) => ({
      id: id.slice(0, 8),
      count,
      percentage: Math.round((count / total.value) * 100)
    }))
})

const topRoutes = computed(() => {
  return Object.entries(routes.value)
    .sort(([, a], [, b]) => b - a)
    .slice(0, 5)
})
</script>

<template>
  <div v-if="authorized" class="connections-widget">
    <h3>Active Users: {{ total }}</h3>
    <div class="versions">
      <h4>By Version</h4>
      <ul>
        <li v-for="v in versionList" :key="v.id">
          {{ v.id }}: {{ v.count }} ({{ v.percentage }}%)
        </li>
      </ul>
    </div>
    <div class="routes">
      <h4>Top Pages</h4>
      <ul>
        <li v-for="[route, count] in topRoutes" :key="route">
          {{ route }}: {{ count }}
        </li>
      </ul>
    </div>
  </div>
  <div v-else>
    Not authorized for live stats
  </div>
</template>
```

### [Deployment Safety Check](#deployment-safety-check)

```
const { total, versions } = useActiveConnections()

const usersOnOldVersions = computed(() => {
  const currentBuildId = useRuntimeConfig().app.buildId
  return Object.entries(versions.value)
    .filter(([id]) => id !== currentBuildId)
    .reduce((sum, [, count]) => sum + count, 0)
})

watch(usersOnOldVersions, (count) => {
  if (count === 0) {
    console.log('All users migrated to latest version!')
  }
})
```

### [Real-time Stats Display](#real-time-stats-display)

```
<script setup lang="ts">
const { total, versions } = useActiveConnections()
const buildId = useRuntimeConfig().app.buildId

const stats = computed(() => {
  const current = versions.value[buildId] || 0
  const outdated = total.value - current
  return {
    current,
    outdated,
    percentCurrent: total.value ? Math.round((current / total.value) * 100) : 0
  }
})
</script>

<template>
  <div class="stats">
    <span>{{ stats.current }} current</span>
    <span>{{ stats.outdated }} outdated</span>
    <span>{{ stats.percentCurrent }}% up to date</span>
  </div>
</template>
```

## [Limitations](#limitations)

- Only works with `updateStrategy: 'sse'` or `updateStrategy: 'ws'`
- Does not support Pusher or Ably adapters (third-party services manage the connections)
- Stats are per-server instance (not aggregated across horizontal scaling)
- Requires server with persistent connections (not compatible with serverless/edge)

[Edit this page](https://github.com/nuxt-seo-pro/nuxt-skew-protection/edit/main/docs/content/3.api/2.use-active-connections.md)

[Markdown For LLMs](https://nuxtseo.com/docs/skew-protection/api/use-active-connections.md)

Did this page help you?

On this page

- [Setup](#setup)
- [Usage](#usage)
- [Returns](#returns)
- [Type Definitions](#type-definitions)
- [Examples](#examples)
- [Limitations](#limitations)

[GitHub](https://github.com/harlan-zw/nuxt-seo) [ Discord](https://discord.com/invite/275MBUBvgP)

###

-
-

Modules

-
-
-
-
-
-
-
-
-

###

-
-
-

###

Nuxt

-
-
-
-
-

Vue

-
-
-
-
-
-
-
-

###

-
-
-
-
-
-
-
-
-
-

Copyright © 2023-2026 Harlan Wilton - [MIT License](https://github.com/harlan-zw/nuxt-seo/blob/main/license) · [mdream](https://mdream.dev)