BS
BleepingSwift
Published on
5 min read

> Detecting When a Screenshot is Taken in SwiftUI

Detecting when users take screenshots can be useful for analytics, security alerts, or triggering specific behaviors in your app. iOS provides a notification that fires whenever a screenshot is captured, making this straightforward to implement.

Basic Screenshot Detection

iOS posts a userDidTakeScreenshotNotification through UIApplication whenever a screenshot is taken. You need to import UIKit and observe this notification:

import SwiftUI
import UIKit

struct ContentView: View {
    var body: some View {
        Text("Take a screenshot!")
            .font(.title)
            .onReceive(NotificationCenter.default.publisher(
                for: UIApplication.userDidTakeScreenshotNotification
            )) { _ in
                print("Screenshot detected!")
                // Handle screenshot event
            }
    }
}

Practical Use Case: Screenshot Analytics

Track when users screenshot content for analytics purposes:

import SwiftUI
import UIKit

struct AnalyticsView: View {
    @State private var screenshotCount = 0

    var body: some View {
        VStack(spacing: 20) {
            Text("Premium Content")
                .font(.title)

            Text("Screenshots taken: \(screenshotCount)")
                .foregroundColor(.secondary)

            Image(systemName: "photo.on.rectangle.angled")
                .font(.system(size: 100))
                .foregroundColor(.blue)
        }
        .onReceive(NotificationCenter.default.publisher(
            for: UIApplication.userDidTakeScreenshotNotification
        )) { _ in
            screenshotCount += 1
            logScreenshotEvent()
        }
    }

    func logScreenshotEvent() {
        // Send analytics event
        print("User took screenshot at \(Date())")
        // Analytics.logEvent("screenshot_taken", parameters: nil)
    }
}

Screenshot Warning for Sensitive Content

Alert users when they screenshot sensitive information:

import SwiftUI
import UIKit

struct SensitiveContentView: View {
    @State private var showWarning = false

    var body: some View {
        VStack {
            Text("Confidential Information")
                .font(.title)
                .padding()

            Text("Account Number: 1234-5678-9012")
                .font(.system(.body, design: .monospaced))
                .padding()

            Text("DO NOT SHARE")
                .foregroundColor(.red)
                .font(.caption)
        }
        .onReceive(NotificationCenter.default.publisher(
            for: UIApplication.userDidTakeScreenshotNotification
        )) { _ in
            showWarning = true
        }
        .alert("Screenshot Detected", isPresented: $showWarning) {
            Button("OK", role: .cancel) { }
        } message: {
            Text("Please keep this information confidential and do not share screenshots.")
        }
    }
}

Using a View Modifier

Create a reusable modifier for screenshot detection:

import SwiftUI
import UIKit

struct ScreenshotDetector: ViewModifier {
    let onScreenshot: () -> Void

    func body(content: Content) -> some View {
        content
            .onReceive(NotificationCenter.default.publisher(
                for: UIApplication.userDidTakeScreenshotNotification
            )) { _ in
                onScreenshot()
            }
    }
}

extension View {
    func onScreenshot(perform action: @escaping () -> Void) -> some View {
        modifier(ScreenshotDetector(onScreenshot: action))
    }
}

// Usage
struct MyView: View {
    var body: some View {
        Text("Content")
            .onScreenshot {
                print("Screenshot taken!")
            }
    }
}

Screenshot with Context Tracking

Track which screen was screenshot:

import SwiftUI
import UIKit

struct ScreenTracker: View {
    @State private var currentScreen = "Home"

    var body: some View {
        NavigationStack {
            VStack {
                Text("Welcome to \(currentScreen)")
                    .font(.title)

                NavigationLink("Go to Details") {
                    DetailView(screenName: "Details")
                }
            }
            .navigationTitle(currentScreen)
        }
        .onScreenshot {
            logScreenshot(screen: currentScreen)
        }
    }

    func logScreenshot(screen: String) {
        print("Screenshot taken on screen: \(screen)")
        // Send to analytics with context
    }
}

struct DetailView: View {
    let screenName: String

    var body: some View {
        Text("Details Screen")
            .onScreenshot {
                print("Screenshot taken on: \(screenName)")
            }
    }
}

Combining Detection with Prevention

Use screenshot detection alongside prevention for sensitive content:

import SwiftUI
import UIKit

struct BankingView: View {
    @State private var showSecurityWarning = false

    var body: some View {
        VStack(spacing: 20) {
            Text("Account Balance")
                .font(.headline)

            // This content should be protected from screenshots
            Text("$10,234.56")
                .font(.system(size: 48, weight: .bold))
                .privacySensitive() // iOS 15+ hides from screenshots
        }
        .onScreenshot {
            showSecurityWarning = true
            // Log security event
            logSecurityEvent("screenshot_attempt")
        }
        .alert("Security Notice", isPresented: $showSecurityWarning) {
            Button("Understood", role: .cancel) { }
        } message: {
            Text("Screenshots of sensitive financial information have been detected. Please keep your account details private.")
        }
    }

    func logSecurityEvent(_ event: String) {
        // Log to security monitoring system
        print("Security event: \(event)")
    }
}

Observable Object Pattern

For app-wide screenshot monitoring:

import SwiftUI
import UIKit
import Combine

class ScreenshotMonitor: ObservableObject {
    @Published var totalScreenshots = 0
    @Published var lastScreenshotDate: Date?

    private var cancellable: AnyCancellable?

    init() {
        cancellable = NotificationCenter.default
            .publisher(for: UIApplication.userDidTakeScreenshotNotification)
            .sink { [weak self] _ in
                self?.handleScreenshot()
            }
    }

    private func handleScreenshot() {
        totalScreenshots += 1
        lastScreenshotDate = Date()

        // Send to analytics
        print("Total screenshots: \(totalScreenshots)")
    }
}

struct AppView: View {
    @StateObject private var screenshotMonitor = ScreenshotMonitor()

    var body: some View {
        VStack {
            Text("Screenshots Taken: \(screenshotMonitor.totalScreenshots)")

            if let date = screenshotMonitor.lastScreenshotDate {
                Text("Last screenshot: \(date.formatted())")
                    .font(.caption)
                    .foregroundColor(.secondary)
            }
        }
    }
}

Important Notes

  • The notification fires after the screenshot is already taken - you cannot prevent the screenshot from this notification alone
  • For preventing screenshots of sensitive content, see Preventing Screenshot Capture in SwiftUI Views
  • Screenshots taken while the app is in the background will still trigger the notification when the app returns to foreground
  • This works for screenshots taken with physical buttons or AssistiveTouch, but not for screen recordings
  • Remember to import UIKit to access UIApplication notifications

Testing

To test screenshot detection:

  1. Run your app on a physical device or simulator
  2. Take a screenshot (iPhone: Volume Up + Side button, Simulator: Cmd+S)
  3. Verify your handler is called

Screenshot detection is useful for analytics and security awareness, but remember that it cannot prevent screenshots from being taken. Combine it with the .privacySensitive() modifier or field-level security for truly sensitive content.

subscribe.sh

// Stay Updated

Get notified when I publish new tutorials on Swift, SwiftUI, and iOS development. No spam, unsubscribe anytime.

>

By subscribing, you agree to our Privacy Policy.