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

# AFK (idle timeout)

> Configure away-from-keyboard detection to disconnect inactive users and free up Unreal Engine instances for others.

AFK detection disconnects inactive viewers to free up workers. The timeout is a **project-level** setting — applied to every session whether the viewer connects via the share link, an iframe, or the Web SDK. See [Session rules](/resources/quick-start-guide/session-rules) for the dashboard configuration.

What the SDK adds is **runtime hooks**: events you can listen for to render a custom warning UI before the disconnect, or override the default timeout for SDK-based sessions.

## Video tutorial

<iframe width="100%" height="420" src="https://www.youtube.com/embed/LcT9zGNRVLY" title="Max Runtime & Inactivity Timeout Tutorial" frameborder="0" allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; fullscreen" allowfullscreen />

## Configuration

Set the timeout duration in seconds (1-7200):

```javascript theme={"dark"}
await StreamPixelApplication({
  appId: 'your-project-id',
  afktimeout: 120,  // 2 minutes
});
```

## How it works

1. The SDK monitors user input (mouse, keyboard, touch, gamepad)
2. After `afktimeout` seconds of inactivity, a warning is shown
3. If the user interacts during the warning countdown, the timer resets
4. If the countdown reaches zero, the stream disconnects

## Events

### `afkWarningActivate`

Fires when the AFK warning should be displayed. Provides a countdown value and a dismiss function.

```javascript theme={"dark"}
pixelStreaming.addEventListener('afkWarningActivate', (e) => {
  const countdown = e.data.countDown;    // Seconds remaining
  const dismiss = e.data.dismissAfk;     // Call this to dismiss the warning

  showAfkWarning(countdown, dismiss);
});
```

<Tip>
  The `dismissAfk` callback from the `afkWarningActivate` event is the key to resetting the AFK timer. Call it when the user confirms they are still active (e.g., clicks an "I'm still here" button) to dismiss the warning and restart the idle countdown.
</Tip>

### `afkWarningUpdate`

Fires every second during the countdown with the updated value.

```javascript theme={"dark"}
pixelStreaming.addEventListener('afkWarningUpdate', (e) => {
  updateCountdown(e.data.countDown);
});
```

### `afkWarningDeactivate`

Fires when the user interacts during the warning, dismissing it.

```javascript theme={"dark"}
pixelStreaming.addEventListener('afkWarningDeactivate', () => {
  hideAfkWarning();
});
```

### `afkTimedOut`

Fires when the countdown reaches zero and the session ends.

```javascript theme={"dark"}
pixelStreaming.addEventListener('afkTimedOut', () => {
  hideAfkWarning();
  showMessage('Session ended due to inactivity.');
});
```

## Custom AFK overlay

The SDK includes a default AFK overlay. To replace it with your own, hide the default and use the events above:

```css theme={"dark"}
/* Hide the default AFK overlay */
#afkOverlay {
  display: none !important;
}
```

<Info>
  You can hide the SDK's built-in AFK overlay with `#afkOverlay { display: none !important; }` in your CSS and build a fully custom overlay using the AFK events listed above.
</Info>

### Full example

```javascript theme={"dark"}
let dismissAfk = null;

pixelStreaming.addEventListener('afkWarningActivate', (e) => {
  dismissAfk = e.data.dismissAfk;
  document.getElementById('afk-overlay').style.display = 'flex';
  document.getElementById('afk-countdown').textContent = e.data.countDown + 's';
});

pixelStreaming.addEventListener('afkWarningUpdate', (e) => {
  document.getElementById('afk-countdown').textContent = e.data.countDown + 's';
});

pixelStreaming.addEventListener('afkWarningDeactivate', () => {
  document.getElementById('afk-overlay').style.display = 'none';
  dismissAfk = null;
});

pixelStreaming.addEventListener('afkTimedOut', () => {
  document.getElementById('afk-overlay').style.display = 'none';
  dismissAfk = null;
  alert('You were disconnected due to inactivity.');
});

// "I'm still here" button
document.getElementById('afk-dismiss-btn').addEventListener('click', () => {
  if (dismissAfk) dismissAfk();
});
```

## Next steps

<CardGroup cols={2}>
  <Card title="Queue system" href="/resources/web-sdk/features/queue-system">
    Show waiting users their position when all UE instances are busy.
  </Card>

  <Card title="Reconnection" href="/resources/web-sdk/features/reconnection">
    Recover from unexpected WebSocket drops automatically.
  </Card>
</CardGroup>
