# How Hyprland Screencasting Permissions Work: Dynamic Permission System Explained

> Understand Hyprland screencasting permissions. Learn how the dynamic permission system manages Wayland screencopy requests with configurable Lua rules.

- Repository: [Hypr Development/Hyprland](https://github.com/hyprwm/Hyprland)
- Tags: internals
- Published: 2026-07-27

---

**Hyprland screencasting permissions are enforced by the `CDynamicPermissionManager`, which intercepts Wayland screencopy protocol requests and either allows, denies, or prompts the user based on configurable Lua rules.**

The hyprwm/Hyprland compositor implements a **dynamic permission system** that governs which clients can capture the screen through the Wayland `screencopy` protocol. Instead of unconditionally granting access, Hyprland evaluates every screencasting request against user-defined rules and runtime prompts. This article breaks down the internal flow from permission identification to the final rendered frame, referencing the actual source implementation.

## The Screencast Permission Pipeline

When a client such as `grim` or `xdg-desktop-portal-hyprland` initiates a screen capture, the request enters a dedicated permission pipeline before any pixel data is shared.

### Identifying the Permission Type

Hyprland classifies screen-sharing operations under the **`PERMISSION_TYPE_SCREENCOPY`** enumerator. This value is defined in the `eDynamicPermissionType` enum inside [`src/managers/permissions/DynamicPermissionManager.hpp`](https://github.com/hyprwm/Hyprland/blob/main/src/managers/permissions/DynamicPermissionManager.hpp). Every incoming screencopy request is tagged with this type so the compositor can apply the correct policy rules.

### Looking Up Rules in CDynamicPermissionManager

The core logic resides in **`CDynamicPermissionManager`**, implemented across [`src/managers/permissions/DynamicPermissionManager.cpp`](https://github.com/hyprwm/Hyprland/blob/main/src/managers/permissions/DynamicPermissionManager.cpp). When a client request arrives, the manager calls `clientPermissionMode` to evaluate the following:

- **Config rules** loaded from the Lua configuration via `hl.permission` entries and the `ecosystem:enforce_permissions` setting. These are stored and checked through `CConfigValue<Config::INTEGER>("ecosystem:enforce_permissions")` and loaded via `addConfigPermissionRule`.
- **Cached decisions** if the user has already responded to a prompt for the client's binary path.
- **Default behavior** of `ask` if no static rule exists, which triggers a one-time user dialog through `CAsyncDialogBox` and remembers the result.

If a rule explicitly allows or denies the binary pattern, the manager returns immediately. Otherwise, the user is prompted and the decision is cached for future requests from the same binary.

## Configuring Hyprland Screencasting Permissions

Administrators and users control screen-sharing behavior through Lua configuration bindings. The system is exposed via `hl.permission` in [`src/config/lua/bindings/LuaBindingsConfigRules.cpp`](https://github.com/hyprwm/Hyprland/blob/main/src/config/lua/bindings/LuaBindingsConfigRules.cpp).

### Setting Static Allow Rules

To bypass interactive prompts for trusted capture tools, add explicit allow rules in your Hyprland Lua config:

```lua
-- Allow grim and the xdg-desktop-portal-hyprland implementation to capture without prompting
hl.permission("/usr/(bin|local/bin)/grim", "screencopy", "allow")
hl.permission("/usr/(lib|libexec|lib64)/xdg-desktop-portal-hyprland", "screencopy", "allow")

```

These patterns match the client binary path and permanently grant **Hyprland screencasting permissions** for the specified executables.

### Denying Screencopy for Specific Clients

Conversely, you can block problematic or untrusted applications:

```lua
-- Prevent a specific tool from ever capturing the screen
hl.permission("/opt/badtool/capture", "screencopy", "deny")

```

### Preserving the Ask Behavior

Setting the policy to `ask` forces Hyprland to request confirmation on the first execution and then cache the answer:

```lua
-- Prompt once per binary, then remember the decision
hl.permission(".*", "screencopy", "ask")

```

If no rule is configured, this is the default behavior.

## Internal Handling of Allowed and Denied Requests

Once `CDynamicPermissionManager` returns a verdict, the screencopy protocol implementation reacts differently depending on the outcome.

### Allowed Screencopy Execution

If the permission mode resolves to allow, the request proceeds normally through **[`src/protocols/Screencopy.cpp`](https://github.com/hyprwm/Hyprland/blob/main/src/protocols/Screencopy.cpp)**. The compositor captures the frame buffer and delivers it to the client without obstruction.

### Denied Request Rendering

If access is denied, Hyprland does not crash or silently fail. Instead, the renderer constructs a dedicated denial texture. Inside **[`src/render/Renderer.cpp`](https://github.com/hyprwm/Hyprland/blob/main/src/render/Renderer.cpp)**, the `m_screencopyDeniedTexture` resource is created to display a *"Permission denied to share screen"* message.

When the `ScreenshareFrame` prepares output in **[`src/managers/screenshare/ScreenshareFrame.cpp`](https://github.com/hyprwm/Hyprland/blob/main/src/managers/screenshare/ScreenshareFrame.cpp)**, it detects the denied state and draws this fallback texture in place of the actual desktop contents. This provides clear visual feedback that the **screencasting permission** was rejected.

## Programmatic Permission Checks

Extensions and protocol implementations can query the current permission state before attempting capture. The following pattern illustrates how Hyprland evaluates a client at runtime:

```cpp
auto mode = PROTO::screencopy->clientPermissionMode(client, PERMISSION_TYPE_SCREENCOPY);
if (mode == PERMISSION_RULE_ALLOW_MODE_ALLOW) {
    // proceed with screencopy
} else {
    // render denied texture (handled internally)
}

```

This check ensures that enforcement remains centralized and consistent across all screen-sharing entry points.

## Summary

- **`PERMISSION_TYPE_SCREENCOPY`** in [`DynamicPermissionManager.hpp`](https://github.com/hyprwm/Hyprland/blob/main/DynamicPermissionManager.hpp) tags every screen-capture request.
- **`CDynamicPermissionManager::clientPermissionMode`** evaluates config rules and cached user decisions, falling back to an interactive `CAsyncDialogBox` prompt.
- **Lua rules** via `hl.permission` in [`LuaBindingsConfigRules.cpp`](https://github.com/hyprwm/Hyprland/blob/main/LuaBindingsConfigRules.cpp) let users statically allow, deny, or ask per binary pattern.
- **Allowed** requests execute through [`src/protocols/Screencopy.cpp`](https://github.com/hyprwm/Hyprland/blob/main/src/protocols/Screencopy.cpp); **denied** requests render a fallback texture created in [`Renderer.cpp`](https://github.com/hyprwm/Hyprland/blob/main/Renderer.cpp) and drawn by [`ScreenshareFrame.cpp`](https://github.com/hyprwm/Hyprland/blob/main/ScreenshareFrame.cpp).

## Frequently Asked Questions

### How do I permanently allow a screen recorder in Hyprland?

Add a Lua config rule using `hl.permission` with the `"allow"` action. For example, grant access to `grim` by writing `hl.permission("/usr/bin/grim", "screencopy", "allow")` in your Hyprland configuration. The binary path is matched against a regex pattern, and the decision is persisted across sessions.

### What happens when a screencast permission is denied?

Hyprland substitutes a dedicated denial texture instead of the desktop image. The texture `m_screencopyDeniedTexture` is created in [`src/render/Renderer.cpp`](https://github.com/hyprwm/Hyprland/blob/main/src/render/Renderer.cpp) and drawn by the `ScreenshareFrame` class in [`src/managers/screenshare/ScreenshareFrame.cpp`](https://github.com/hyprwm/Hyprland/blob/main/src/managers/screenshare/ScreenshareFrame.cpp), clearly indicating that screen sharing is blocked.

### Where does Hyprland store screencasting permission rules?

Static rules are defined in the Lua configuration through the `hl.permission` binding exposed in [`src/config/lua/bindings/LuaBindingsConfigRules.cpp`](https://github.com/hyprwm/Hyprland/blob/main/src/config/lua/bindings/LuaBindingsConfigRules.cpp). Dynamic, cached answers from user prompts are managed at runtime by `CDynamicPermissionManager` in [`src/managers/permissions/DynamicPermissionManager.cpp`](https://github.com/hyprwm/Hyprland/blob/main/src/managers/permissions/DynamicPermissionManager.cpp).

### Can I set a global ask policy for all screencopy clients?

Yes. Use `hl.permission(".*", "screencopy", "ask")` to match all binaries. Because the default behavior is already to ask once per unrecognized binary and remember the response, this rule explicitly enforces the prompt policy across every client.