Skip to content

TrustedForm iOS Mobile SDK

John Johnson edited this page Oct 3, 2025 · 20 revisions

TrustedForm Certify Mobile SDK - Quick Start Guide

The TrustedForm Certify Mobile SDK is designed to provide documentation of lead generation events that can be used to show evidence of prior express written consent given by consumers who desire to receive marketing communications. Following the instructions below will create a TrustedForm certificate that can be retained for your own records and/or distributed to lead buyers. The example code provided is a template to help you get started. It should be adapted to align with the specific requirements for your business and setup of your mobile application.

The iOS version supports both UIKit and SwiftUI frameworks, offering seamless integration for lead publishers to certify leads generated from their mobile applications.

After you have created certificates, use TrustedForm Retain to access and store it in your ActiveProspect account.


Installation

Swift Package Manager

Add a package by selecting File → Add Packages… in Xcode's menu bar.

Search for the Trusted Form SDK using the repo's URL:

https://github.com/activeprospect/trustedform-ios-sdk

Next, set the Dependency Rule to be Up to Next Major Version.

Then, select Add Package.


Complete Implementation Flow

Overview of the TrustedForm Process

The TrustedForm SDK follows a specific flow to ensure proper lead certification:

  1. Configuration → 2. Certificate Creation → 3. Tracking Setup → 4. Form Interaction → 5. Screenshot Capture → 6. Cleanup

Step-by-Step Requirements

Step 1: Configuration (Required)

  • When: Application startup
  • Where: AppDelegate or App initializer
  • Requirements: Valid app ID, access token, Application context
  • Result: SDK is ready for use

Step 2: Certificate Creation (Required)

  • When: Before starting any form tracking
  • Where: ViewController or SwiftUI View before displaying form
  • Requirements: Valid configuration, network connectivity, valid access token
  • Result: Certificate object for tracking

Step 3: Tracking Setup (Required)

  • When: After successful certificate creation
  • Where: ViewController or SwiftUI View after certificate creation
  • Requirements: Valid certificate, valid view hierarchy
  • Result: Tracking is active and ready

Step 4: Form Interaction (Automatic)

  • When: User interacts with form elements
  • Where: Anywhere in the tracked view
  • Requirements: Tracking must be active, elements must have proper roles
  • Result: User interactions are tracked and recorded

Step 5: Screenshot Capture (Automatic + Manual)

  • When: During form interactions and on demand
  • Where: Throughout the tracked view
  • Requirements: Tracking active, valid view hierarchy, sufficient storage
  • Result: Screenshots captured and uploaded

Step 6: Cleanup (Required)

  • When: Form submission or view dismissal
  • Where: viewWillDisappear or onDisappear
  • Requirements: Valid certificate reference
  • Result: Resources cleaned up, tracking stopped

Implementation

1. Initialize the SDK

SwiftUI

import SwiftUI
import TrustedForm

@main
struct SwiftUIDemoApp: App {
    init() {
        configureTrustedFormSDK()
    }

    var body: some Scene {
        WindowGroup {
            AppContent()
        }
    }
}

extension SwiftUIDemoApp {
    private func configureTrustedFormSDK() {
        // Configure the SDK
        TrustedForm.default.configure(
            appId: "YOUR_APP_ID",
            accessToken: "YOUR_ACCESS_TOKEN"
        )

        // Optional: Enable verbose logging for development
        #if DEBUG
            TrustedForm.enableVerboseLogging()
        #endif
    }
}

UIKit

import UIKit
import TrustedForm

class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Configure the SDK
        TrustedForm.default.configure(
            appId: "YOUR_APP_ID",
            accessToken: "YOUR_ACCESS_TOKEN"
        )

        // Optional: Enable verbose logging for development
        #if DEBUG
            TrustedForm.enableVerboseLogging()
        #endif

        return true
    }
}

Configuration Requirements

Required Parameters:

  • appId: Your unique application identifier
  • accessToken: Your ActiveProspect API access token

Important Notes:

  • Configuration must be called before any other TrustedForm operations
  • The SDK will throw TFError.unconfigured if accessed before configuration
  • Configuration is typically done once in your AppDelegate or App initializer
  • All parameters are required and must be valid for the SDK to function properly

2. Create and Track Certificates

SwiftUI

import SwiftUI
import TrustedForm

struct AppContent: View {
    @State private var certificate: Certificate? = nil

    var body: some View {
        Text("Hello World!")
            .onAppear {
                guard certificate == nil else { return }
                
                Task {
                    await setupTracking()
                }
            }
    }

    private func setupTracking() async {
        do {
            // Create a certificate
            let certificate = try await TrustedForm.default.createCertificate()

            // Start tracking
            TrustedForm.default.startTracking(for: certificate)

            self.certificate = certificate

        } catch {
            print("Failed to create certificate: \(error.localizedDescription)")
        }
    }

    private func cleanup() {
        // Stop tracking when form is submitted or view disappears
        if let certificate = certificate {
            TrustedForm.default.stopTracking(for: certificate)
        }
    }
}

UIKit

import UIKit
import TrustedForm

class ViewController: UIViewController {
    private var certificate: Certificate? = nil

    override func viewDidLoad() {
        super.viewDidLoad()
        Task {
            await setupTracking()
        }
    }

    private func setupTracking() async {
        do {
            // Create a certificate
            let certificate = try await TrustedForm.default.createCertificate()

            // Start tracking
            TrustedForm.default.startTracking(for: certificate)

            self.certificate = certificate

        } catch {
            print("Failed to create certificate: \(error.localizedDescription)")
        }
    }

    private func cleanup() {
        // Stop tracking when form is submitted or view disappears
        if let certificate = certificate {
            TrustedForm.default.stopTracking(for: certificate)
        }
    }
}

Certificate Creation Requirements

Prerequisites for Certificate Creation:

  • TrustedForm must be properly configured
  • Valid network connectivity
  • Valid access token with proper permissions
  • iOS application context must be available

What Happens During Certificate Creation:

  • SDK obtains device information (OS version, screen dimensions, device type)
  • SDK retrieves public IP address
  • SDK generates unique certificate ID
  • Certificate is created on TrustedForm servers
  • Local certificate object is returned for tracking

Tracking Requirements

Prerequisites for startTracking():

  • Valid certificate object (from successful createCertificate())
  • Valid view hierarchy
  • Network connectivity for initial setup

What Happens When Tracking Starts:

  • Touch listeners are set up on the view
  • Screenshot service is initialized
  • Event controller is activated
  • Initial screenshot is captured
  • Form interaction tracking begins

Important Notes:

  • Only one tracking session can be active at a time
  • If tracking is already active, calling startTracking() again will stop the previous session
  • Tracking must be stopped when the form is submitted or view is dismissed
  • Screenshots are automatically captured during tracking

3. Add Consent Tags Using TF Element Roles

Use TFElementRole to assign specific roles to form elements for tracking consent information.

Available Element Roles

The SDK provides several element roles for different types of form elements:

  • consentTrackedText - For text input fields (name, email, phone, etc.)
  • consentTrackedInput - For checkboxes, toggles, and other input controls
  • consentLanguage - For consent text and terms
  • consentLanguageInput - For consent checkboxes
  • consentOptedAdvertiserInput - For advertiser selection checkboxes
  • consentOptedAdvertiserName - For advertiser name labels
  • consentTrackedField - For descriptive fields
  • submit - For submit buttons

SwiftUI Example

import SwiftUI
import TrustedForm

struct ConsentForm: View {
    @State private var firstName = ""
    @State private var lastName = ""
    @State private var email = ""
    @State private var agreeToTerms = false
    @State private var advertiserConsent = false
    @State private var certificate: Certificate?
    let submissionId = UUID().uuidString

    var body: some View {
        Form {
            // Text Field - First Name
            TextField("First Name", text: $firstName)
                .tfElementRole(
                    .consentTrackedText(
                        submissionId: submissionId,
                        label: "First Name"
                    ),
                    binding: $firstName
                )

            // Text Field - Last Name
            TextField("Last Name", text: $lastName)
                .tfElementRole(
                    .consentTrackedText(
                        submissionId: submissionId,
                        label: "Last Name"
                    ),
                    binding: $lastName
                )

            // Text Field - Email
            TextField("Email", text: $email)
                .tfElementRole(
                    .consentTrackedText(
                        submissionId: submissionId,
                        label: "Email"
                    ),
                    binding: $email
                )

            // Consent Text
            Text("I agree to the terms and conditions")
                .tfElementRole(
                    .consentLanguage(
                        submissionId: submissionId
                    )
                )

            // Consent Checkbox
            Toggle("I agree to terms", isOn: $agreeToTerms)
                .tfElementRole(
                    .consentTrackedInput(
                        submissionId: submissionId,
                        label: "Terms Agreement"
                    ),
                    binding: $agreeToTerms
                )

            // Advertiser Consent
            Toggle(isOn: $advertiserConsent) {
                Text("I want to receive email updates")
                    .tfElementRole(
                        .consentOptedAdvertiserName(
                            submissionId: submissionId,
                            index: 0
                        )
                    )
            }
            .tfElementRole(
                .consentOptedAdvertiserInput(
                    submissionId: submissionId,
                    label: "I want to receive email updates",
                    index: 0
                ),
                binding: $advertiserConsent
            )

            // Submit Button
            Button("Submit") {
                // Handle form submission
            }
            .tfElementRole(.submit(submissionId: submissionId))
        }
        .onAppear {
            Task {
                do {
                    certificate = try await TrustedForm.default.createCertificate()
                    if let certificate = certificate {
                        TrustedForm.default.startTracking(for: certificate)
                    }
                } catch {
                    print("Failed to create certificate: \(error)")
                }
            }
        }
        .onDisappear {
            if let certificate = certificate {
                TrustedForm.default.stopTracking(for: certificate)
            }
        }
    }
}

UIKit Example

import UIKit
import TrustedForm

class ConsentFormViewController: UIViewController {
    private var certificate: Certificate?
    private let submissionId = UUID().uuidString

    private lazy var firstNameField: UITextField = {
        let field = UITextField()
        field.placeholder = "First Name"
        field.borderStyle = .roundedRect
        field.tfElementRole = .consentTrackedText(
            submissionId: submissionId,
            label: "First Name"
        )
        return field
    }()

    private lazy var lastNameField: UITextField = {
        let field = UITextField()
        field.placeholder = "Last Name"
        field.borderStyle = .roundedRect
        field.tfElementRole = .consentTrackedText(
            submissionId: submissionId,
            label: "Last Name"
        )
        return field
    }()

    private lazy var emailField: UITextField = {
        let field = UITextField()
        field.placeholder = "Email"
        field.borderStyle = .roundedRect
        field.tfElementRole = .consentTrackedText(
            submissionId: submissionId,
            label: "Email"
        )
        return field
    }()

    private lazy var consentTextLabel: UILabel = {
        let label = UILabel()
        label.text = "I agree to the terms and conditions"
        label.tfElementRole = .consentLanguage(
            submissionId: submissionId
        )
        return label
    }()

    private lazy var termsSwitch: UISwitch = {
        let toggle = UISwitch()
        toggle.tfElementRole = .consentTrackedInput(
            submissionId: submissionId,
            label: "Terms Agreement"
        )
        return toggle
    }()

    private lazy var advertiserDescriptionLabel: UILabel = {
        let label = UILabel()
        label.text = "I want to receive email updates"
        label.tfElementRole = .consentOptedAdvertiserName(
            submissionId: submissionId,
            index: 0
        )
        return label
    }()

    private lazy var advertiserButton: UIButton = {
        let button = UIButton()
        button.tfElementRole = .consentOptedAdvertiserInput(
            submissionId: submissionId,
            label: "I want to receive email updates",
            index: 0
        )
        return button
    }()

    private lazy var submitButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("Submit", for: .normal)
        button.tfElementRole = .submit(submissionId: submissionId)
        button.addTarget(self, action: #selector(submitTapped), for: .touchUpInside)
        return button
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
        setupTracking()
    }

    private func setupUI() {
        // Add and layout subviews
        // (Layout constraints omitted for brevity)
    }

    private func setupTracking() {
        Task {
            do {
                certificate = try await TrustedForm.default.createCertificate()
                if let certificate = certificate {
                    TrustedForm.default.startTracking(for: certificate)
                }
            } catch {
                print("Failed to create certificate: \(error)")
            }
        }
    }

    @objc private func submitTapped() {
        // Handle form submission
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        if let certificate = certificate {
            TrustedForm.default.stopTracking(for: certificate)
        }
    }
}

4. Mark Sensitive Fields

Mark fields containing sensitive information to ensure they are masked in screenshots:

SwiftUI

TextField("SSN", text: $ssn)
    .tfElementRole(
        .consentTrackedText(
            submissionId: submissionId,
            label: "SSN"
        ),
        binding: $ssn
    )
    .sensitive()

UIKit

let ssnField = UITextField()
ssnField.placeholder = "SSN"
ssnField.tfElementRole = .consentTrackedText(
    submissionId: submissionId,
    label: "SSN"
)
ssnField.isSensitive = true

Example usage:

// Credit Card Field
TextField("Credit Card", text: $creditCard)
    .tfElementRole(
        .consentTrackedText(
            submissionId: submissionId,
            label: "credit-card"
        ),
        binding: $creditCard
    )
    .sensitive()

5. Add Screenshots to Certificates

The SDK automatically captures screenshots during form interactions, but you can also manually trigger screenshot capture:

// Manual screenshot capture
if let certificate = certificate {
    try? TrustedForm.default.addScreenshot(to: certificate)
}

Screenshot Requirements

Prerequisites for Screenshot Capture:

  • Tracking must be active (startTracking() called)
  • Valid view hierarchy
  • View must be in a visible state
  • Sufficient storage space for screenshot files

When screenshots are automatically captured:

  • When tracking starts (startTracking())
  • When tracking stops (stopTracking())
  • When manually triggered (addScreenshot(to:))
  • When submit buttons are tapped (buttons with TFElementRole.submit)

Screenshot Process:

  1. Capture: Screenshot is taken of the current view
  2. Masking: Sensitive fields (marked with .sensitive() or isSensitive = true) are automatically masked
  3. Storage: Screenshot is saved locally with timestamp
  4. Upload: Screenshot is uploaded to TrustedForm servers asynchronously
  5. Cleanup: Local files are cleaned up after successful upload

Screenshot Features:

  • Sensitive fields are automatically masked with configurable color
  • Screenshots are stored locally and uploaded to TrustedForm servers
  • Multiple screenshots can be captured per certificate
  • Screenshots include timestamps and form state
  • Automatic retry mechanism for failed uploads
  • Local storage cleanup after successful upload

Manual Screenshot Capture:

// Capture screenshot on specific user action
func onFormFieldChanged() {
    if let certificate = certificate {
        try? TrustedForm.default.addScreenshot(to: certificate)
    }
}

// Capture screenshot before form submission
func onSubmitForm() {
    if let certificate = certificate {
        try? TrustedForm.default.addScreenshot(to: certificate)
    }
    // Proceed with form submission
}

// Capture screenshot on important form milestones
func onFormStepComplete() {
    if let certificate = certificate {
        try? TrustedForm.default.addScreenshot(to: certificate)
    }
}

Screenshot Troubleshooting:

  • Ensure tracking is active before capturing screenshots
  • Check that the view has a valid hierarchy
  • Verify storage permissions if screenshots fail to save
  • Monitor network connectivity for upload failures

6. Advanced Form Tracking Example

Here's a more comprehensive example showing multiple element types:

SwiftUI Advanced Example

import SwiftUI
import TrustedForm

struct AdvancedConsentForm: View {
    @State private var firstName = ""
    @State private var lastName = ""
    @State private var email = ""
    @State private var phone = ""
    @State private var ssn = ""
    @State private var isMilitary = false
    @State private var advertiserConsents = [false, false, false]
    @State private var agreeToTerms = false
    @State private var certificate: Certificate?
    let submissionId = UUID().uuidString

    var body: some View {
        Form {
            // Name Fields
            TextField("First Name", text: $firstName)
                .tfElementRole(
                    .consentTrackedText(
                        submissionId: submissionId,
                        label: "First Name"
                    ),
                    binding: $firstName
                )

            TextField("Last Name", text: $lastName)
                .tfElementRole(
                    .consentTrackedText(
                        submissionId: submissionId,
                        label: "Last Name"
                    ),
                    binding: $lastName
                )

            // Contact Fields
            TextField("Email", text: $email)
                .tfElementRole(
                    .consentTrackedText(
                        submissionId: submissionId,
                        label: "Email"
                    ),
                    binding: $email
                )

            TextField("Phone", text: $phone)
                .tfElementRole(
                    .consentTrackedText(
                        submissionId: submissionId,
                        label: "Phone"
                    ),
                    binding: $phone
                )

            // Sensitive Field
            TextField("SSN", text: $ssn)
                .tfElementRole(
                    .consentTrackedText(
                        submissionId: submissionId,
                        label: "SSN"
                    ),
                    binding: $ssn
                )
                .sensitive()

            // Military Status Toggle
            Toggle("Are you or your spouse a military veteran?", isOn: $isMilitary)
                .tfElementRole(
                    .consentTrackedInput(
                        submissionId: submissionId,
                        label: "Military Status"
                    ),
                    binding: $isMilitary
                )

            // Consent Language
            Text("By submitting this form, you agree to our terms and conditions and consent to receive marketing communications.")
                .tfElementRole(
                    .consentLanguage(
                        submissionId: submissionId
                    )
                )

            // Advertiser Consent Checkboxes
            Text("Select advertisers you'd like to hear from:")
                .font(.caption)

            let advertisers = ["Advertiser A", "Advertiser B", "Advertiser C"]
            ForEach(0..<advertisers.count, id: \.self) { index in
                Toggle(isOn: $advertiserConsents[index]) {
                    Text(advertisers[index])
                        .tfElementRole(
                            .consentOptedAdvertiserName(
                                submissionId: submissionId,
                                index: index
                            )
                        )
                }
                .tfElementRole(
                    .consentOptedAdvertiserInput(
                        submissionId: submissionId,
                        label: advertisers[index],
                        index: index
                    ),
                    binding: $advertiserConsents[index]
                )
            }

            // Submit Button
            Button("Submit Application") {
                // Handle form submission
            }
            .tfElementRole(.submit(submissionId: submissionId))
        }
        .onAppear {
            Task {
                do {
                    certificate = try await TrustedForm.default.createCertificate()
                    if let certificate = certificate {
                        TrustedForm.default.startTracking(for: certificate)
                    }
                } catch {
                    print("Failed to create certificate: \(error)")
                }
            }
        }
        .onDisappear {
            if let certificate = certificate {
                TrustedForm.default.stopTracking(for: certificate)
            }
        }
    }
}

7. Complete ViewController Integration Example

Here's a complete example showing how to integrate TrustedForm in a ViewController with proper lifecycle management:

import UIKit
import TrustedForm

class TrustedFormViewController: UIViewController {
    private var certificate: Certificate?
    private let submissionId = UUID().uuidString

    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
        setupTracking()
    }

    private func setupUI() {
        // Setup your UI elements here
        // Add form fields, buttons, etc.
    }

    private func setupTracking() {
        Task {
            do {
                certificate = try await TrustedForm.default.createCertificate()
                if let certificate = certificate {
                    TrustedForm.default.startTracking(for: certificate)
                }
            } catch {
                print("Failed to create certificate: \(error)")
            }
        }
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        if let certificate = certificate {
            TrustedForm.default.stopTracking(for: certificate)
        }
    }
}

Key Points for ViewController Implementation:

  • Use viewDidLoad for certificate creation and tracking setup
  • Single Form: Stop tracking in viewWillDisappear when form is complete
  • Multi-Page Form: Keep tracking across pages, only stop when form is submitted
  • Always call stopTracking when the view disappears
  • Only one tracking session can be active at a time

Best Practices

  1. Always start tracking before displaying forms - Ensure tracking is active before users interact with form elements
  2. Stop tracking when forms are submitted or dismissed - Clean up resources to prevent memory leaks
  3. Use appropriate element roles - Choose the correct TFElementRole type for each form component
  4. Mark sensitive fields appropriately - Use .sensitive() modifier or isSensitive = true for fields containing PII
  5. Maintain unique submission IDs - Use different submission IDs for different forms or form steps
  6. Handle errors gracefully - Always handle certificate creation errors
  7. Clean up resources - Stop tracking in viewWillDisappear or onDisappear
  8. Test thoroughly - Verify that all form interactions are properly tracked
  9. Use meaningful labels - Provide descriptive labels for better certificate documentation
  10. Consider form state - Track form state changes and user interactions comprehensively

Troubleshooting

Common Issues

  1. Certificate creation fails

    • Verify your access token is valid
    • Check network connectivity
    • Ensure all required configuration parameters are provided
  2. Tracking not working

    • Ensure startTracking() is called after certificate creation
    • Verify form elements have proper TFElementRole modifiers
    • Check that the view hierarchy is valid
  3. Screenshots not captured

    • Ensure tracking is active when screenshots are needed
    • Check that the view has a valid hierarchy
    • Verify storage permissions if needed
    • Ensure view is in visible state
    • Check network connectivity for upload
  4. Sensitive fields not masked

    • Ensure .sensitive() modifier or isSensitive = true is applied to sensitive fields
    • Verify the field is properly registered with TrustedForm
    • Check that tracking is active when field is marked sensitive
  5. Certificate creation fails

    • Verify access token is valid and has proper permissions
    • Check network connectivity
    • Ensure all configuration parameters are correct
    • Verify application context is available
  6. Tracking stops unexpectedly

    • Check for view lifecycle issues
    • Verify certificate is still valid
    • Ensure no other tracking session is interfering
    • Check for memory pressure or system resource issues

API Reference

TrustedForm Configuration

TrustedForm.default.configure(
    appId: String,        // Your application ID
    accessToken: String   // Your access token
)

Certificate Management

// Create a certificate
let certificate = try await TrustedForm.default.createCertificate()

// Start tracking
TrustedForm.default.startTracking(for: certificate)

// Stop tracking
TrustedForm.default.stopTracking(for: certificate)

// Add screenshot
try TrustedForm.default.addScreenshot(to: certificate)

Element Roles

// Text input fields
TFElementRole.consentTrackedText(submissionId: String, label: String)

// Checkboxes and toggles
TFElementRole.consentTrackedInput(submissionId: String, label: String, index: Int? = nil)

// Consent language
TFElementRole.consentLanguage(submissionId: String, index: Int? = nil)

// Submit buttons
TFElementRole.submit(submissionId: String, label: String, index: Int? = nil)

// Advertiser consent
TFElementRole.consentOptedAdvertiserInput(submissionId: String, label: String, index: Int? = nil)
TFElementRole.consentOptedAdvertiserName(submissionId: String, index: Int? = nil)

SwiftUI Modifiers

// Text field tracking
.tfElementRole(_ role: TFElementRole, binding: Binding<String>)

// Toggle tracking
.tfElementRole(_ role: TFElementRole, binding: Binding<Bool>)

// Button tracking
.tfElementRole(_ role: TFElementRole)

// Sensitive field masking
.sensitive()

UIKit Properties

// Element role assignment
view.tfElementRole = .consentTrackedText(submissionId: String, label: String)

// Sensitive field marking
view.isSensitive = true