Coinme Risk SDK for iOS Native Apps

Introduction

The iOS Coinme Risk Engine SDK is a Swift library, distributed privately via Cloudsmith, that allows you to interact with the Coinme Risk Engine from your application. It provides utilities that allow you to integrate against the Coinme risk engine for the various transactional flows in your application so that Coinme may appropriately assess transactional risk when processing transactions.

ℹ️

Note:

In order to utilize Coinme transactional services from within your application, you must implement and use the Coinme risk engine SDK.

What is it?

The Coinme risk engine aggregates data about user behavior for your application. It collects:

  • Device data such as the type of device, OS name and version, etc.
  • Location data such as where the user is connecting from.
  • Connection data such as if the user is using a proxy or VPN, etc.
  • Behavioral data such as how a user is interacting with your application, how quickly they are entering data into fields, use of clipboard functions, etc.

This data is used to determine the relative riskiness of the user / transaction.

⚠️

Why is Risk Tagging Important?

Risk tagging allows the SDK to track user interactions tied to specific actions within your application. When an element is tagged, the risk engine can better assess whether a user is behaving normally or if suspicious automation patterns are detected.

As an example, if the risk engine determines that the user location changes suddenly via a VPN to access a region restricted transaction type, then the engine may determine automation is at play and may rank the transaction as high risk.


Implementing the iOS SDK

⚠️

This package is not public

You will need an auth token in order to install it. You may obtain this by working with the Coinme business development team.


What You'll Need to Get Started

Before integrating the SDK, you will need the following credentials from the Coinme business development team:

CredentialRequired ForNotes
Cloudsmith auth tokenAccessing the libraryRequired to access the private library in Cloudsmith
clientIdRiskEngineSetupOptionsEnvironment-specific — you will need one for development and one for production
partnerIdgetPartnerSessionTag()Passed via GetPartnerSessionTagOptions, this is your Partner identifier needed for integration with Coinme APIs

⚠️ You will need two clientIds, one for your development builds and one for your prod builds; you may obtain these from the Coinme business development team. It is very important that you pass the correct mode and clientId properties into the risk engine based on development or production usage, otherwise you may not stream your behavioral data to the correct environment, which can severely impact the risk engine’s ability to assess risk. This would ultimately negatively impact your transaction approvals.



Installation

Set Your Entitlement Token

Create a coinme.properties file in your project root directory:

COINME_TOKEN=<YOUR_ENTITLEMENT_TOKEN>

Replace <YOUR_ENTITLEMENT_TOKEN> with the token provided by the Coinme business development team. Do not commit this file to version control.

Important: Add coinme.properties to your .gitignore to keep your token secure:

coinme.properties

Add the SDK Repository and Dependency to your project

Update your Podfile:

source 'https://github.com/CocoaPods/Specs.git'

# Read token from properties file
def read_token
  properties_file = File.join(File.dirname(__FILE__), 'coinme.properties')
  if File.exist?(properties_file)
    File.foreach(properties_file) do |line|
      key, value = line.split('=')
      return value.strip if key.strip == 'COINME_TOKEN'
    end
  end
  ENV['COINME_TOKEN'] || ''
end

token = read_token

plugin 'cocoapods-cloudsmith', {
  'source' => "https://dl.cloudsmith.io/#{token}/coinme/coinme-sdk-mobile/cocoapods/index.json"
}

target 'YourApp' do
  use_frameworks!
  pod 'CoinmeRiskSDK', '~> 1.0.0'
end
source 'https://github.com/CocoaPods/Specs.git'

token = ENV['COINME_TOKEN'] || ''

plugin 'cocoapods-cloudsmith', {
  'source' => "https://dl.cloudsmith.io/#{token}/coinme/coinme-sdk-mobile/cocoapods/index.json"
}

target 'YourApp' do
  use_frameworks!
  pod 'CoinmeRiskSDK', '~> 1.0.0'
end

If installing via an Environment Variable, you will also need to set the environment variable in your shell

export COINME_TOKEN=<YOUR_ENTITLEMENT_TOKEN>

App Store Requirements

Before releasing your application with the Coinme Risk SDK, update your App Store Connect settings in your Apple developer portal.

App Privacy — Data Collection

In App Store Connect > App Privacy, declare the following:

  1. Data Collection: Select "Yes, we collect data from this app"

  2. Location:

    • Select Coarse Location and/or Precise Location (depending on your app settings)
    • Purpose: App Functionality
    • Reason: Required for fraud detection and prevention
  3. Identifiers — Device ID:

    • Purpose: App Functionality
    • Check: Yes, device ID is linked to user identity

Privacy Policy

Update your App Store privacy policy to include the following disclosure:

ℹ️

Required Privacy Policy Language

For fraud protection purposes only, (1) we collect your Battery Usage, Device Identifier, Device Storage, and location information; (2) we also collect enough information to determine if you are trying to fake your current location by using a VPN or other location-spoofing tools.


Required Permissions

Add location permissions to your Info.plist:

<dict>
  ...
  <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
  <string>We use your location to verify transactions and prevent fraud.</string>
  <key>NSLocationWhenInUseUsageDescription</key>
  <string>We use your location to verify transactions and prevent fraud.</string>
</dict>

This is a required permission for fraud detection and should be requested at runtime. Ensure your app handles the permission request appropriately for optimal risk assessment and to avoid issues from App Store Review.


Implementation

Privacy & Compliance Notice

Important: If you use the Behavior Biometrics feature (enableBehaviourBiometrics = true), please ensure that your end users agree to your privacy policy before you begin collecting their Behavior Biometric data. This is required for compliance with privacy regulations.


Configuration Options

RiskEngineSetupOptions

OptionTypeRequiredDescription
modeModeYesUsed to point to environment .test or .prod
clientIdStringYesYour environment-specific Client ID
partnerIdStringYesPartner Identifier
customerIdString?NoCustomer/User's identifier
sessionKeyString?NoSession key (automatically generated if not provided)
flowFlowType?NoCurrent User flow (Onboarding, CardTransaction, or CardLinking)
regionAppRegionNoYour app's region of service (.default(US), .ca, .eu, .au, .in)
enableBehaviorBiometricsBoolNoEnabled behavior tracking (default: true)
enableClipboardTrackingBoolNoEnable clipboard tracking (default: false)
enableFieldTrackingBoolNoEnable automatic field tracking (default: true)
setCloudEntitlementsBoolNoEnable iCloud feature (default: false, requires additional setup)

FlowType Options

  • FlowType.Onboarding - New user registration flow
  • FlowType.CardTransaction - Payment/card transaction flow
  • FlowType.CardLinking - Adding payment methods flow

sessionKey

The sessionKey is a unique identifier for tracking a specific user session.

Once a key is provided for the set up, it will be cached for the duration of the app's active session. If no value is provided, the key will be automatically generated.

You will want to invoke .getPartnerSessionTag() to get an updated value that our backend will use to associate collected user data and risk score. Failure to call this and get the expected session key value may result in loss of data for accurate risk assessment.

Using .updateCoinmeRiskEngine() with a new key will override and update the cached value.

To clear a sessionKey, you may call .resetStoredSessionKey()

⚠️

Important:

When you call getPartnerSessionTag(), the returned webSessionID automatically becomes the active session key. All subsequent calls to updateCoinmeRiskEngine() will use this session key unless you explicitly provide a different one.


getPartnerSessionTag()

Retrieve the session tag from the backend API. The resulting webSessionID is automatically used to update the CoinmeRiskEngine configuration.

try await CoinmeRiskEngine.getPartnerSessionTag(options: GetPartnerSessionTagOptions) -> SessionTagData

Request body parameters for GetPartnerSessionTagOptions:

ParamTypeRequiredDescription
partnerIdStringYesYour partner identifier
accountIdStringYesThe customer ID
fingerprintStringYesThe device fingerprint
additionalHeadersDict<String, String>NoAdditional headers that may be included if needed by the backend
timeoutIntNoRequest timeout in milliseconds (default: 10000)


Initialize the SDK

Initialize the Risk Engine in your app's initialization:

import CoinmeRiskSDK

let options = RiskEngineSetupOptions(
    mode: .prod,  // Use .test for testing
    clientId: "your-client-id",
    enableBehaviourBiometrics: true,
    enableFieldTracking: false  // Set to false for manual tracking
)

CoinmeRiskEngine.setupCoinmeRiskEngine(options: options)

Update the SDK

You can update the configuration with flow, sessionKey and customerId options:

CoinmeRiskEngine.updateCoinmeRiskEngine(
    RiskEngineUpdateOptions(
        sessionKey: "new-session-key",
        flow: .cardTransaction,
        customerId: "customer-id"
  )
)

Submit Data Before Transactions

Submits all collected behavioral and device date to the backend for risk assessment. Use callback version to ensure data is submitted before making subsequent API calls.

CoinmeRiskEngine.submit(
    onSuccess: {
        // Data successfully submitted - safe to proceed with transaction API call
        processPayment()
    },
    onError: { error in
        print("Risk SDK submission failed: \(error)")
        handleError(error)
    }
)

What it collects:

  • Sensor data (motion, orientation, pressure)
  • Behavioral biometrics (typing patterns, interaction timing)
  • Device context (clipboard activity, focus patterns)
  • Page/screen engagement metrics

When to call:

  • Before payment/transaction API calls
  • Before critical actions (login, signup, money transfer)
  • After form completion or user interaction flow

Other Utility Methods

Get Current Config

Returns the current runtime configuration.

CoinmeRiskEngine.getCoinmeRiskEngineConfig() -> RiskEngineUpdateOptions

Reset Session

Resets the stored session key.

CoinmeRiskEngine.resetStoredSessionKey()

Reset SDK

Clears the singleton instance and cleans up resources.

CoinmeRiskEngine.reset()

Manual Input Field Tracking

ℹ️

If you choose to manually track input fields, first disabled automatic field tracking in the configuration. This can be done by ensuring enableFieldTracking = false when you set options for the CoinmeRiskEngine.

How to set up custom TextField for tracking:

import SwiftUI
import CoinmeRiskSDK

struct LoginView: View {
    @State private var email = ""
    @FocusState private var isEmailFocused: Bool

    var body: some View {
        TextField("Email", text: $email)
            .focused($isEmailFocused)
            .onChange(of: email) { newValue in
                CoinmeRiskEngine.trackTextChange(viewId: "email", text: newValue)
            }
            .onChange(of: isEmailFocused) { isFocused in
                CoinmeRiskEngine.trackFocusChange(viewId: "email", isFocus: isFocused)
            }
    }
}
// In your UIViewController
class LoginViewController: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var emailTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        emailTextField.delegate = self
    }

    // UITextFieldDelegate - Track focus changes
    func textFieldDidBeginEditing(_ textField: UITextField) {
        CoinmeRiskEngine.trackFocusChange(viewId: "email", isFocus: true)
    }

    func textFieldDidEndEditing(_ textField: UITextField) {
        CoinmeRiskEngine.trackFocusChange(viewId: "email", isFocus: false)
    }

    // UITextFieldDelegate - Track text changes
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,
                   replacementString string: String) -> Bool {
        let currentText = textField.text ?? ""
        let newText = (currentText as NSString).replacingCharacters(in: range, with: string)
        CoinmeRiskEngine.trackTextChange(viewId: "email", text: newText)
        return true
    }
}

Be descriptive when assigning a value for viewId ("email", "password", "debitCardNumber", etc)


Tracking Methods

Track text changes to an input field

CoinmeRiskEngine.trackTextChange(viewId: String, text: String)

Track focus change to a field

CoinmeRiskEngine.trackFocusChange(viewId: String, isFocus: Bool)

Note: Be sure to use the same viewId for both trackTextChange() and trackFocusChange() if they are used to reference the same text field or other custom UI component.


Optional Features


Enable Location Service

Initialize Apple's LocationManager to provide live location updates:

import CoreLocation

class LocationService: NSObject, CLLocationManagerDelegate {
    let locationManager: CLLocationManager?

    override init() {
        locationManager = CLLocationManager()
        locationManager?.requestWhenInUseAuthorization()

        super.init()

        locationManager?.delegate = self
    }

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        if status == .authorizedWhenInUse {
            if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) {
                if CLLocationManager.isRangingAvailable() {
                    let latitude = manager.location?.coordinate.latitude
                    let longitude = manager.location?.coordinate.longitude

                    print("Location: \(latitude ?? 0), \(longitude ?? 0)")
                }
            }
        }
    }
}

Enable Wi-Fi Information Tracking

Wi-Fi BSSID and SSID can provide additional location signals.

  1. Enable Location Services (required)
  2. In Xcode:
    1. Go to your target scheme
    2. Click Signing & Capabilities
    3. Click + Capability
    4. Add Access WiFi Information

Enable iCloud Record ID

iCloud Record ID remains consistent across devices that are associated with the same Apple account.

  1. In Xcode
      1. Go to your target scheme
      2. Click Signing & Capabilities
      3. Click + Capability
      4. Add iCloud
      5. Select CloudKit service
      6. Choose your container
  2. Set the flag in the SDK configuration:
    1. let options = RiskEngineSetupOptions(
          mode: .prod,
          clientId: "your-client-id",
          setCloudEntitlements: true  // Must be true for iCloud features
      )
🚧

Warning: DO NOT set setCloudEntitlements to true unless CloudKit is properly configured, or the SDK will crash.


Enable Biometric Authentication Detection

Detect the use of FaceID and TouchID

Update your Info.plist

<dict>
  ...
  <key>NSFaceIDUsageDescription</key>
  <string>Face ID is used to verify your identity.</string>
</dict>