iOS SDK

A simple guide to integrate Fingerprint's device intelligence platform in your native iOS apps.

In this guide, you will learn to

  • Include the iOS SDK in your mobile apps.
  • Get a visitorId.
  • Read the SDK response.
  • Configure the SDK as per your needs.
  • Specify additional metadata in your identification request.
  • Handle errors

For a complete example of how to use this SDK in your app, please visit the GitHub repo of our demo app.

Prerequisites

  1. Sign up for an account with Fingerprint to get your API key.
  2. Xcode 14.1 or higher. See App Store submission requirements for more information.

Including the SDK in your app

Add the SDK as a dependency.

// Add the below lines to Package.swift
let package = Package(
  // ...
  dependencies: [
    .package(url: "https://github.com/fingerprintjs/fingerprintjs-pro-ios", from: "2.0.0")
  ]
  // ...
)
# Add the below line to the Podfile
pod 'FingerprintPro', '~> 2.0'

Getting a visitorId

To get a visitorId, you need the public API key that you obtained when signing up for an account with Fingerprint. You can find this API key in your dashboard at App Settings > API Keys.

Here is an example that shows you how to get a visitorId:

import FingerprintPro

// Configure the SDK
// The 'region' must match the region associated with your API key
let region: Region = .ap
// For custom subdomain or proxy integration, use .custom(domain:) region that lets you
// specify a custom endpoint.
// let region: Region = .custom(domain: "https://example.com")
let configuration = 
  Configuration(apiKey: <your-api-key>, region: region, extendedResponseFormat: false)

// Initialize the SDK with the configuration created above
let client = FingerprintProFactory.getInstance(configuration)

do {
  // Get a 'visitorId'
  let visitorId = try await client.getVisitorId()
  print(visitorId)
} catch {
  // process error
}

Reading the response

The function FingerprintClientProviding.getVisitorIdResponse() returns the response in a FingerprintResponse object. By default, this object contains the following fields:

  • requestId - String. An identifier that uniquely identifies this particular request to FingerprintClientProviding.getVisitorId().
  • visitorId - String. An identifier that uniquely identifies the device.
  • confidence - Float. A score that indicates the probability of this device being accurately identified. The value ranges from 0 to 1.

Configuring the SDK

Using the Configuration object, it is possible to configure the SDK as per your requirements. As of now, the following options are supported:

region

Type: Region.

Default value: Region.global

This option allows you to specify a region where you want your data to be stored and processed. This region must be the same as the one you specified when registering your app with Fingerprint. Use Region.custom(domain:) enumeration case to specify a custom endpoint, particularly when you have set up either a custom sub-domain or a proxy integration. See region for more information.

extendedResponseFormat

Type: Bool

Default value: false

When set to true, in addition to those fields returned by default, the FingerprintResponse object will also contain the following fields:

  • visitorFound - Bool. Indicates if this device has already been encountered by your app.
  • ipAddress - String. The IPv4 address of the device.
  • ipLocation - IPLocation. Indicates the location as deduced from the IP address.
  • firstSeenAt, lastSeenAt - Timestamp. See Useful timestamps.

Specifying linkedId and tag

Similar to the JS Agent for the browser, the iOS SDK also supports providing custom metadata along with an identification request. To learn more about this capability, please see Linking and tagging information.

Here is an example that shows you how to associate your identification request with an account ID and additional metadata:

let client = FingerprintProFactory.getInstance("<your-api-key>")

// Associate an account number to this request 
var metadata = Metadata(linkedId: "accountID")
// Associate additional metadata to this request
metadata.setTag("purchase", forKey: "actionType")
metadata.setTag(10, forKey: "purchaseCount")

// Get a 'visitorId'
let visitorId = try? await client.getVisitorId(metadata) 

Handling errors

The SDK provides an FPJSError enumeration that helps you identify the reasons behind an unsuccessful identification request. Here is an example that shows you how to handle errors in your app:

do {
  visitorId = try await client.getVisitorId()
} catch FPJSError.networkError(let error) {
  print("Network error: \(error.localizedDescription)")
  // Handle network error (e.g. check Internet connection and try again)
} catch {
  print("Could not obtain visitor ID due to an error: \(error.localizedDescription)")
}

Data Classes

Configuration

/// A type that represents a single key/value parameter with the library integration
/// information.
public typealias IntegrationInfo = (String, String)

/// A library configuration specifying various options for configuring the Fingerprint Client
/// instance.
public struct Configuration {
  /// A public API key obtained from [Fingerprint Dashboard](https://dashboard.fingerprint.com).
  public var apiKey: String
  /// The Fingerprint Server API region.
  public var region: Region
  /// An array of key/value parameters identifying a particular library integration.
  ///
  /// This property should only be used when creating an integration wrapper around the library
  /// (e.g. Flutter or React Native wrapper).
  public var integrationInfo: [IntegrationInfo]
  /// A Boolean value that determines whether the backend should respond with an extended
  /// result. See
  /// [developer documentation](https://dev.fingerprint.com/docs/ios-sdk#extendedresponseformat
  public var extendedResponseFormat: Bool

  /// Creates a library configuration object with the specified parameters.
  ///
  /// - Note: API keys are region-specific, so make sure you have selected the correct region
  ///         when calling this initializer.
  ///
  /// - Parameters:
  ///   - apiKey: A public API key obtained from 
  ///             [Fingerprint Dashboard](https://dashboard.fingerprint.com).
  ///   - region: The Fingerprint Server API region. Defaults to ``Region/global``.
  ///   - integrationInfo: An array of key/value parameters identifying a particular library
  ///                      integration. Defaults to an empty array.
  ///   - extendedResponseFormat: A Boolean value that determines whether the backend should 
  ///                             respond with an extended result. Defaults to `false`.
  public init(
      apiKey: String,
      region: Region = .global,
      integrationInfo: [IntegrationInfo] = [],
      extendedResponseFormat: Bool = false
  ) {
    self.apiKey = apiKey
    self.region = region
    self.integrationInfo = integrationInfo
    self.extendedResponseFormat = extendedResponseFormat
  }
}

Error

/// An error type that indicates problems with the device fingerprinting.
public enum FPJSError: Error {
  /// An error that indicates the server URL is invalid.
  case invalidURL
  /// An error that indicates the integration info URL parameters are invalid.
  case invalidURLParams
  /// An API error returned by the Fingerprint backend.
  case apiError(APIError)
  /// A network error.
  case networkError(Error)
  /// A JSON parsing error that indicates the request body is malformed.
  case jsonParsingError(Error)
  /// An error that indicates the response is invalid.
  case invalidResponseType
  /// Unknown error.
  case unknownError
}

/// A Fingerprint Server API error.
public struct APIError: Decodable {
  /// The API version.
  public let version: String
  /// The identifier that uniquely identifies a request.
  public let requestId: String
  /// The error details.
  public let error: ErrorDetails?
}

public extension APIError {
  /// The details about a reason that the API request failed.
  struct ErrorDetails: Decodable {
    /// The error code, as defined by ``APIErrorType`` enum.
    public let code: APIErrorType?
    /// A detailed error message.
    public let message: String
  }
}

/// An enumeration representing known Fingerprint API error types.
public enum APIErrorType: String, Decodable {
  /// The API token is missing.
  case tokenRequired = "TokenRequired"
  /// Invalid API token.
  case tokenNotFound = "TokenNotFound"
  /// The API token expired.
  case tokenExpired = "TokenExpired"
  /// Malformed request body or parameters.
  case requestCannotBeParsed = "RequestCannotBeParsed"
  /// Request failed.
  case failed = "Failed"
  /// A server connection timeout.
  case requestTimeout = "RequestTimeout"
  /// Request rate limit exceeded.
  case tooManyRequests = "TooManyRequests"
  /// The API key does not match a selected region.
  case wrongRegion = "WrongRegion"
  /// Subscription is not active for the provided API key.
  case subscriptionNotActive = "SubsriptionNotActive"
  case originNotAvailable = "OriginNotAvailable"
  case headerRestricted = "HeaderRestricted"
  case notAvailableForCrawlBots = "NotAvailableForCrawlBots"
  case notAvailableWithoutUA = "NotAvailableWithoutUA"
  case unsupportedVersion = "UnsupportedVersion"
  case installationMethodRestricted = "InstallationMethodRestricted"
  case hostnameRestricted = "HostnameRestricted"
}

IPLocation

/// The IP address information.
public struct IPLocation: Equatable, Codable {
  /// The city component of the IP address.
  public let city: IPGeoInfo?
  /// The country component of the IP address.
  public let country: IPGeoInfo?
  /// The continent component of the IP address.
  public let continent: IPGeoInfo?
  /// The longitude in degrees.
  public let longitude: Float?
  /// The latitude in degrees.
  public let latitude: Float?
  /// The postal code of the IP address.
  public let postalCode: String?
  /// The time zone of the IP address.
  public let timezone: String?
  /// The approximate accuracy radius in kilometers around the IP address location.
  public let accuracyRadius: UInt?
  /// The subdivisions (such as a county or other region) associated with the IP address.
  public let subdivisions: [IPLocationSubdivision]?
}

/// A structure containing the location name and code.
///
/// It can represent a country, city or continent.
public struct IPGeoInfo: Equatable, Codable {
  /// The location name.
  public let name: String
  /// The area, country or continent code.
  public let code: String?
}

/// A structure describing the location's subdivision.
public struct IPLocationSubdivision: Equatable, Codable {
  /// The ISO code.
  let isoCode: String
  /// The subdivision name.
  let name: String
}

Region

/// The Fingerprint Server API region.
public enum Region {
  /// A default Global (US) region.
  case global
  /// A European (EU) region.
  case eu
  /// An Asia-Pacific (APAC) region.
  case ap
  /// A custom endpoint, as defined by the `domain` associated value.
  case custom(domain: String)
}

Timestamp

/// A data structure representing the timestamp.
public struct SeenAt: Equatable, Codable {
  /// The timestamp associated with the Fingerprint Server API region.
  public let global: Date?
  /// The timestamp associated with an active Fingerprint application.
  public let subscription: Date?
}