# AFK (Idle Timeout)

AFK (Away From Keyboard) detection disconnects inactive users to free up UE instance resources for others.

## Video Tutorial

{% embed url="<https://youtube.com/watch?v=LcT9zGNRVLY>" %}
Max Runtime & Inactivity Timeout Tutorial
{% endembed %}

## Configuration

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

```javascript
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
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);
});
```

{% hint style="success" %}
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.
{% endhint %}

### `afkWarningUpdate`

Fires every second during the countdown with the updated value.

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

### `afkWarningDeactivate`

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

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

### `afkTimedOut`

Fires when the countdown reaches zero and the session ends.

```javascript
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
/* Hide the default AFK overlay */
#afkOverlay {
  display: none !important;
}
```

{% hint style="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.
{% endhint %}

### Full Example

{% code lineNumbers="true" %}

```javascript
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();
});
```

{% endcode %}
