# Permissions Prompt Customization

The permissions prompt view automatically appears when users join a call without the necessary camera or microphone permissions. Stream Video SDK allows you to fully customize or disable this component through the `ViewFactory` protocol.

## Default Behavior

By default, the SDK displays a prompt when:

- The user needs camera permission for video calls but hasn't granted it
- The user needs microphone permission but hasn't granted it
- The call's capabilities require these permissions

The prompt appears as an overlay in the `CallTopView` and provides a direct link to the app's settings.

## Disabling the Permissions Prompt

If you prefer to handle permissions differently or don't want to show any prompt, you can disable it entirely:

```swift
class NoPermissionsPromptViewFactory: ViewFactory {

    func makePermissionsPromptView(call: Call?) -> some View {
        EmptyView()
    }
}

/// Then use your custom factory when creating the call view:
let viewFactory = NoPermissionsPromptViewFactory()
let callView = CallView(
    viewFactory: viewFactory,
    viewModel: viewModel
)
```

## Custom Styled Permissions Prompt

You can create a completely custom permissions prompt with your own design language:

```swift
struct CustomPermissionsPromptView: View {
    @Injected(\.urlNavigator) private var urlNavigator

    let call: Call?
    @ObservedObject private var permissions = InjectedValues[\.permissions]
    @State private var isHidden = false

    private var requiresCameraPermission: Bool {
        call?.state.ownCapabilities.contains(.sendVideo) ?? false
    }

    private var requiresMicrophonePermission: Bool {
        call?.state.ownCapabilities.contains(.sendAudio) ?? false
    }

    private var isMissingCameraPermission: Bool {
        requiresCameraPermission && !permissions.hasCameraPermission
    }

    private var isMissingMicrophonePermission: Bool {
        requiresMicrophonePermission && !permissions.hasMicrophonePermission
    }

    var body: some View {
        if (isMissingCameraPermission || isMissingMicrophonePermission) && !isHidden {
            VStack(spacing: 12) {
                Image(systemName: "exclamationmark.shield.fill")
                    .font(.largeTitle)
                    .foregroundColor(.orange)

                Text(permissionText)
                    .font(.headline)
                    .multilineTextAlignment(.center)

                HStack(spacing: 16) {
                    Button("Open Settings") {
                        try? urlNavigator.openSettings()
                    }
                    .buttonStyle(.borderedProminent)

                    Button("Dismiss") {
                        withAnimation {
                            isHidden = true
                        }
                    }
                    .buttonStyle(.bordered)
                }
            }
            .padding()
            .background(
                RoundedRectangle(cornerRadius: 16)
                    .fill(.ultraThinMaterial)
            )
            .transition(.move(edge: .top).combined(with: .opacity))
        }
    }

    private var permissionText: String {
        switch (isMissingCameraPermission, isMissingMicrophonePermission) {
        case (true, true):
            return "Camera and microphone access required"
        case (true, false):
            return "Camera access required"
        case (false, true):
            return "Microphone access required"
        default:
            return ""
        }
    }
}

class CustomPermissionsViewFactory: ViewFactory {

    func makePermissionsPromptView(call: Call?) -> some View {
        CustomPermissionsPromptView(call: call)
    }
}
```

## Best Practices

When customizing the permissions prompt, consider these best practices:

1. **User Experience**: Keep the prompt non-intrusive but visible enough for users to notice
2. **Clear Messaging**: Clearly explain why permissions are needed for the best call experience
3. **Easy Actions**: Provide direct links to Settings so users can quickly grant permissions
4. **Dismissible**: Allow users to dismiss the prompt if they choose to continue without permissions
5. **Persistence**: Decide whether the prompt should reappear or stay dismissed for the session

## Accessing Permission State

You can access the current permission state through the injected `PermissionStore`:

```swift
@ObservedObject private var permissions = InjectedValues[\.permissions]

// Check individual permissions
let hasCameraAccess = permissions.hasCameraPermission
let hasMicAccess = permissions.hasMicrophonePermission
```

## Related Components

- [`ViewFactory`](/video/docs/ios/ui-components/customizing-views/): The protocol for customizing UI components


---

This page was last updated at 2026-05-13T13:39:04.375Z.

For the most recent version of this documentation, visit [https://getstream.io/video/docs/ios/ui-cookbook/permissions-prompt-customization/](https://getstream.io/video/docs/ios/ui-cookbook/permissions-prompt-customization/).