Skip to content

User Consent

Part of the Human Scoring use case.

The SDK records how the user interacts with your app, so by default it records nothing until the user agrees. The SDK ships a ready-made consent alert for SwiftUI and UIKit, and you can replace it with your own UI without losing the guarantee.

When to use it

  • Always, unless your app already obtains consent before creating the DeaSdk — in that case, set requireConsent: false
  • To change the wording of the alert, or translate it
  • To let the user withdraw consent from a settings screen

Prerequisites

  • The SDK is installed and started. See the Quick Start.
  • The SwiftUI alert needs iOS 15 or later. The UIKit alert works from iOS 13.

Usage

Show the built-in alert (UIKit)

import DeaSDK
import UIKit

class HomeViewController: UIViewController {
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        Dea.sdk?.requestConsent(from: self) { agreed in
            print("DEA consent: \(agreed)")
        }
    }
}
  • The answer is stored on the device. Once the user has answered, later calls call completion with the stored answer straight away and show nothing, so it is safe to call on every launch.
  • The alert has two buttons, both answers. It cannot be dismissed by tapping outside.

Show the built-in alert (SwiftUI)

import DeaBase
import DeaSDK
import SwiftUI

struct HomeView: View {
    @State private var askingConsent = false

    var body: some View {
        let content = Text("Home")
            .onAppear {
                if let dea = Dea.sdk, !dea.consent.isAnswered {
                    askingConsent = true
                }
            }

        if let dea = Dea.sdk {
            content.deaConsent(dea.consent, asking: $askingConsent) { agreed in
                print("DEA consent: \(agreed)")
            }
        } else {
            content
        }
    }
}

The deaConsent modifier shows the alert whenever asking becomes true; it does not check the stored answer itself. Set asking only when consent.isAnswered is false, as above, or the user is asked on every launch.

Change the wording

import DeaSDK

let copy = ConsentCopy(
    title: "Help us keep bots out",
    body: "We measure how you interact with the app to tell people apart from bots.",
    recorded: ["Where you touch, and how hard", "How the phone moves in your hand"],
    notRecorded: ["What you type", "What's on your screen"],
    closing: "You can change this at any time in Settings.",
    accept: "Allow",
    decline: "Not now"
)

// UIKit
Dea.sdk?.requestConsent(from: self, copy: copy) { _ in }

// SwiftUI
// content.deaConsent(dea.consent, asking: $askingConsent, copy: copy) { _ in }

Pass an empty array to recorded or notRecorded to hide that section. Make sure the lists stay true for your app.

Use your own UI

Draw your own screen or onboarding step, then record the answer:

import DeaSDK

Dea.sdk?.setConsent(true)  // the user agreed
Dea.sdk?.setConsent(false) // the user declined

Recording starts or stops as soon as setConsent returns.

Read the current answer

import DeaBase
import DeaSDK

if let consent = Dea.sdk?.consent {
    print(consent.isAnswered) // false until the user has answered
    print(consent.isGranted)  // true only if the user agreed
    print(consent.decision)   // unknown, granted or denied
}

Be notified when the answer changes

import DeaBase
import DeaSDK

let stopListening = Dea.sdk?.consent.onChange { decision in
    print("DEA consent is now \(decision)")
}

// Later, to stop being notified:
stopListening?()
import DeaSDK

Dea.sdk?.setConsent(false)

Recording stops immediately. The session is kept, so if the user agrees again, recording continues in the same session.

Ask again

import DeaBase
import DeaSDK

Dea.sdk?.consent.forget()

forget() clears the stored answer, so the next requestConsent call (or your isAnswered check) asks again — for example when a different account signs in on the same device. Unlike declining, it is not an answer.

Shared devices

When a different person may use the device each session (a kiosk, a test device), do not store the answer:

// UIKit
Dea.sdk?.requestConsent(from: self, remember: false) { _ in }

// SwiftUI
// content.deaConsent(dea.consent, asking: $askingConsent, remember: false) { _ in }

// Your own UI
Dea.sdk?.setConsent(true, remember: false)

With remember: false the UIKit alert is shown on every call and the answer is kept for this run only.

Examples

A settings switch (SwiftUI)

import DeaBase
import DeaSDK
import SwiftUI

struct DeaConsentToggle: View {
    @State private var granted = Dea.sdk?.consent.isGranted ?? false

    var body: some View {
        Toggle("Bot protection", isOn: $granted)
            .disabled(Dea.sdk == nil)
            .onChange(of: granted) { value in
                Dea.sdk?.setConsent(value)
            }
    }
}

A settings switch (UIKit)

import DeaBase
import DeaSDK
import UIKit

class PrivacySettingsViewController: UIViewController {
    private let toggle = UISwitch()

    override func viewDidLoad() {
        super.viewDidLoad()
        toggle.isOn = Dea.sdk?.consent.isGranted ?? false
        toggle.isEnabled = Dea.sdk != nil
        toggle.addTarget(self, action: #selector(toggled), for: .valueChanged)
        view.addSubview(toggle)
    }

    @objc private func toggled() {
        Dea.sdk?.setConsent(toggle.isOn)
    }
}

API

Member Returns Description
DeaSdk.requestConsent(from:copy:remember:completion:) Void UIKit. Shows the alert if needed and calls completion with the answer
View.deaConsent(_:asking:copy:remember:onAnswer:) some View SwiftUI, iOS 15+. Shows the alert while asking is true and records the answer
DeaSdk.setConsent(_:remember:) Void Records the answer
DeaSdk.consent Consent The current answer
Consent.isAnswered Bool Whether the user has answered
Consent.isGranted Bool Whether the user agreed
Consent.decision ConsentDecision .unknown, .granted or .denied
Consent.forget() Void Clears the stored answer
Consent.onChange(_:) () -> Void Calls the listener when the answer changes; call the returned closure to stop