Example usage of FingerprintJS Pro inside a iOS WebView.

Overview

FingerprintJS

Discord server

FingerprintJS Pro iOS Integrations

An example app and packages demonstrating FingerprintJS Pro capabilities on the iOS platform. The repository illustrates how to retrieve a FingerprintJS Pro visitor identifier in a native mobile app. These integrations communicate with the FingerprintJS Pro API and require browser token. If you are interested in the Android platform, you can also check our FingerprintJS Pro Android integrations.

There are two typical use cases:

  • Using our native library to retrieve a FingerprintJS Pro visitor identifier in the native code OR
  • Retrieving visitor identifier using signals from the FingerprintJS Pro browser agent in the webview on the JavaScript level combined with vendor identifier.

Using the external library to retrieve a FingerprintJS Pro visitor identifier

This integration approach uses our library FingerprintJSPro. It collects various signals from the iOS system, sends them to the FingerprintJS Pro API for processing, and retrieves an accurate visitor identifier.

1. Installation

CocoaPods

Specify the following dependency in your Podfile:

pod 'FingerprintJSPro', '~> 1.1.0'

Swift Package Manager

Add the following dependency to your Package.swift.

dependencies: [
    .package(url: "https://github.com/fingerprintjs/fingerprintjs-pro-ios-integrations", .upToNextMajor(from: "1.1.0"))
]

2. Import

import FingerprintJSPro

3. Get the visitor identifier

You can find your browser api token in your dashboard.

FingerprintJSProFactory
    .getInstance(
        token: "your-browser-token",
        endpoint: nil, // optional
        region: nil // optional
    )
    .getVisitorId { result in
        switch result {
        case let .failure(error):
            print("Error: ", error.localizedDescription)
        case let .success(visitorId):
            print("Success: ", visitorId)
        }
    }

Params

  • token: string - API token from the FingerprintJS dashboard
  • endpoint: URL? - nil for default endpoint, possible format for custom endpoint: URL(string: "https://fp.yourdomain.com")
  • region: String? - nil for the Global region, eu for the European region

Tags support

FingerprintJSProFactory
    .getInstance(
        token: "your-browser-token",
        endpoint: nil, // optional
        region: nil // optional
    )
    .getVisitorId(tags: ["sessionId": sessionId]) { result in
        switch result {
        case let .failure(error):
            print("Error: ", error.localizedDescription)
        case let .success(visitorId):
            print("Success: ", visitorId)
        }
    }

Using inside a webview with JavaScript

This approach uses signals from FingerprintJS Pro browser agent together with iOS device vendor identifier. The vendor identifier is added to the tag field in the given format. FingerprintJS Pro browser agent adds an additional set of signals and sents them to the FingerprintJS Pro API. Eventually, the API returns accurate visitor identifier.

1. Add a JavaScript interface to your webview

let vendorId = UIDevice.current.identifierForVendor.flatMap { "'\($0.uuidString)'" } ?? "undefined"

let script = WKUserScript(source: "window.fingerprintjs = { 'vendorId' : \(vendorId) }",
                          injectionTime: .atDocumentStart,
                          forMainFrameOnly: false)

webView.configuration.userContentController.addUserScript(script) // the webview should contain a webpage with injected and configured fingerprintjs-pro

2. Setup the JavaScript FingerprintJS Pro integration in your webview

function initFingerprintJS() {
  // Initialize an agent at application startup.
  const fpPromise = FingerprintJS.load({
    token: "your-browser-token",
    endpoint: "your-endpoint", // optional
    region: "your-region", // optional
  });

  // Get the visitor identifier when you need it.
  fpPromise
    .then((fp) =>
      fp.get({
        environment: {
          deviceId: window.fingerprintjs.vendorId, // use vendor ID as device ID
          type: "ios",
        }
      })
    )
    .then((result) => console.log(result.visitorId));
}

Params

You can find your browser token in your dashboard. Params format and properties are the same as in JS agent

The full example content view for SwiftUI with configured fingerprintjs-pro might look like:

import SwiftUI
import WebKit
 
struct ContentView: View {
    var body: some View {
        Webview(url: URL(string: "https://eager-hermann-4ea017.netlify.app")!) // this URL should refer to the webpage with injected and configured fingerprintjs-pro
    }
}
 
struct Webview: UIViewRepresentable {
    let url: URL
 
    func makeUIView(context: UIViewRepresentableContext<Webview>) -> WKWebView {
        let webview = WKWebView()
 
        let vendorId = UIDevice.current.identifierForVendor.flatMap { "'\($0.uuidString)'" } ?? "undefined"
        
        let script = WKUserScript(source: "window.fingerprintjs = { 'vendorId' : \(vendorId) }", injectionTime: .atDocumentStart, forMainFrameOnly: false)
 
        webview.configuration.userContentController.addUserScript(script) 
 
        let request = URLRequest(url: self.url, cachePolicy: .returnCacheDataElseLoad)
        webview.load(request)
 
        return webview
    }
 
    func updateUIView(_ webview: WKWebView, context: UIViewRepresentableContext<Webview>) {
        let request = URLRequest(url: self.url, cachePolicy: .returnCacheDataElseLoad)
        webview.load(request)
    }
}

Additional Resources

FingerprintJS Pro documentation

License

This library is MIT licensed.

Comments
  • Error:  Not available for this origin

    Error: Not available for this origin

    Hi I am coding by example. The VisitorId can be obtained at the beginning. Yesterday on June 26, this error was suddenly reported, and it returned to normal in the afternoon. However, it has been reporting this error(Error: Not available for this origin). This error happens on simulator and iPhone. I'm running Xcode 13, hope you have time to reply thank you!

    opened by yihoushuhang 2
  • Error Domain=RBSServiceErrorDomain Code=1

    Error Domain=RBSServiceErrorDomain Code=1 "target is not running or doesn't have entitlement com.apple.runningboard.assertions.webkit"

    Following is my FingerprintJS code to get visitorId: `import UIKit import FingerprintJSPro

    class ViewController: UIViewController {

    let userActivityTracker = UserActivityTracker()
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        let token = "xxxxx"
        FingerprintJSProFactory
            .getInstance(
                token: token,
                endpoint: nil, // optional
                region: nil // optional
            )
            .getVisitorId { result in
                switch result {
                case let .failure(error):
                    print("Error: ", error.localizedDescription)
                case let .success(visitorId):
                    print("Success: ", visitorId)
                }
            }
    }
    
    
    @IBAction func onClicked(_ sender: Any) {
        print("Button clicked from ViewController")
    }
    

    }`

    This is the only ViewController (blank screen). After running the project I got following errors in my console:- Error Domain=RBSServiceErrorDomain Code=1 "target is not running or doesn't have entitlement com.apple.runningboard.assertions.webkit" UserInfo={NSLocalizedFailureReason=target is not running or doesn't have entitlement com.apple.runningboard.assertions.webkit}

    I'm running Xcode 13, UIKit framework with Swift 5

    opened by vkvashistha 2
  • WebView approach not working

    WebView approach not working

    Whem I follow the guidelines for the webview approach, vendorId tag is not reflected.

    Steps to reproduce:

    1. Create view in swiftUI:
    import SwiftUI
    import WebKit
     
    struct ContentView: View {
        var body: some View {
            Webview(url: URL(string: "https://eager-hermann-4ea017.netlify.app")!)
        }
    }
     
    struct Webview: UIViewRepresentable {
        let url: URL
     
        func makeUIView(context: UIViewRepresentableContext<Webview>) -> WKWebView {
            let webview = WKWebView()
     
            let vendorId = UIDevice.current.identifierForVendor?.uuidString ?? "undefined"
    
            let script = WKUserScript(source: "window.fingerprintjs.vendorId = \(vendorId)", injectionTime: .atDocumentStart, forMainFrameOnly: false)
     
            webview.configuration.userContentController.addUserScript(script)
     
            let request = URLRequest(url: self.url, cachePolicy: .returnCacheDataElseLoad)
            webview.load(request)
     
            return webview
        }
     
        func updateUIView(_ webview: WKWebView, context: UIViewRepresentableContext<Webview>) {
            let request = URLRequest(url: self.url, cachePolicy: .returnCacheDataElseLoad)
            webview.load(request)
        }
    }
    
    1. Create hmlt page with FPJS on the URL specified in the Webview(url: URL(string: "https://eager-hermann-4ea017.netlify.app")!)
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta name="description" content="Webpage description goes here" />
        <meta charset="utf-8" />
        <title>Change_me</title>
      </head>
      <body>
        <div class="container"></div>
        <script>
          const vendorId =
            window.fingerprintjs && window.fingerprintjs.vendorId
              ? window.fingerprintjs.vendorId
              : 'not-in-ios-context'
    
          function initFingerprintJS() {
            // Initialize an agent at application startup.
            const fpPromise = FingerprintJS.load({
              token: 'tQUwQQOuG9TNwqc6F4I2',
              region: 'eu',
              endpoint: 'https://fp.martinmakarsky.com',
            })
    
            // Get the visitor identifier when you need it.
            fpPromise
              .then((fp) =>
                fp.get({
                  tag: {
                    deviceId: vendorId,
                    deviceType: 'ios',
                  },
                  linkedId: 'makma',
                  extendedResult: true,
                })
              )
              .then((result) => {
                console.log(result.visitorId);
                var el = document.createElement("h1");
                el.innerText = result.visitorId;
                document.body.appendChild(el);
              })
          }
        </script>
        <script
          async
          src="https://cdn.jsdelivr.net/npm/@fingerprintjs/fingerprintjs-pro@3/dist/fp.min.js"
          onload="initFingerprintJS()"
        ></script>
      </body>
    </html>
    
    1. Run iOS app, get visitorId and check tag on server API Expected output:
    ...
                "linkedId": "makma",
                "timestamp": 1629209018949,
                "time": "2021-08-17T14:03:38Z",
                "url": "https://eager-hermann-4ea017.netlify.app/",
                "tag": {
                    "deviceId": "vendor-id-from-ios-context",
                    "deviceType": "ios"
                }
    ...
    

    Actual output:

    ...
                "linkedId": "makma",
                "timestamp": 1629209018949,
                "time": "2021-08-17T14:03:38Z",
                "url": "https://eager-hermann-4ea017.netlify.app/",
                "tag": {
                    "deviceId": "not-in-ios-context",
                    "deviceType": "ios"
                }
    ...
    

    Note: I've also tried to set window object after webview.load(request)

    Questions and suggestions:

    • is webview approach documented well?
    • is swift UI somehow specific?
    • should it be window.fingerprintjs.vendorId or window.FingerprintJS.vendorId?
    • I'd like to see full webview example in readme e.g. for SwiftUI
    opened by makma 2
  • How to get additional  data in response such as ipLocation?

    How to get additional data in response such as ipLocation?

    I see fingerprintjs-pro-android provide configuration params "extendedResult"=true, to get get additional data to app. But I don't find any similar methods exposed for fingerprintjs-pro-ios. Does that means in iOS extended result not supported? Is there any way to get that details too?

    opened by vkvashistha 1
  • Minor improvements from testing

    Minor improvements from testing

    • adjust token string quotes in example, backtics are not valid swift syntax
    • add info about region: "eu" for europe, nil for global
    • NSAppTransportSecurity
    • custom enpoint: URL(string: "https://mysite.com")
    • error handling?
    opened by makma 0
  • docs: document repository

    docs: document repository

    I've tried to explain all the concepts and differences (including Pro API vs client side fingerprinting only). I'd rename repo to fingerprintjs-pro-ios-integrations. Reason:

    I omitted the webview keyword on purpose. For external folks (with webview in the name), it might sound like this repo contains only the webview use cases which is not true.

    TODO:

    • rename repo
    • update description
    • test the package according to readme snippets - TBD once packages are released
    • add info about TLS

    Consideration: Pls consider renaming library package fpjs-ios-wv. I assume wv stands for webview - this might be confusing for developers. I'd also like to see a mention of our Pro product in the name. Proposed name: fingerprintjs-pro-ios-integrations.

    opened by makma 0
  • Xcode preview stopped working

    Xcode preview stopped working

    I'm having trouble with the SwiftUI Preview in Xcode 14. I have the same problem with the Example.

    HumanReadableSwiftError
    
    SettingsError: noExecutablePath(<IDESwiftPackageStaticLibraryProductBuildable:ObjectIdentifier(0x0000600038a5a100):'FingerprintPro'>)
    

    Does anyone have any idea what it could be?

    opened by adrianorezena 1
Owner
FingerprintJS
Fraud detection API for the Internet
FingerprintJS
Matthew Asaminew 0 Jan 25, 2022
Stateful WebView for SwiftUI.

Stateful SwiftUI WebView for iOS and MacOS Fully functional, SwiftUI-ready WebView for iOS 13+ and MacOS 10.15+. Actions and state are both delivered

Gordan Glavaš 35 Dec 14, 2022
Single Webview project for xcode in swift

Single Webview project for xcode in swift An xcode project that with single webview(UIWebView) that opens external URL, for hybrid web app debug or te

null 0 Dec 11, 2021
redis-pro 是一款 redis 轻量客户端管理工具, 采用SwiftUI 编写

redis-pro 是一款 redis 轻量客户端管理工具, 采用SwiftUI 编写

cmushroom 583 Jan 5, 2023
Pro Counter, SwiftUI WatchOS, Open Source Project

Countio | SwiftUI WatchOS App App Screenshots || What is Countio Countio is simple WatchOS App made with Swiftly SwiftUI. You can count anything quick

Dc7 4 Feb 7, 2022
How to handle HelaPay links inside UIWebView and WKWebView

Handling හෙළPay Links Setup Clone this repo. git clone https://github.com/PayHereDevs/helapay-link-handler.git To properly handle හෙළPay Links in you

PayHereDevs 0 Feb 9, 2022
Assignment 2 - A fully functional example in the CardinalKit-Example directory

Assignment 2 - A fully functional example in the CardinalKit-Example directory

GaitMate 1 Jan 31, 2022
Simple app to show usage of SwiftUI and Combine

Podcasts Simple app to show usage of SwiftUI and Combine. The app shows a list of podcasts fetched from listennotes and it can be played. Status: Work

Alberto Penas Amor 27 Oct 4, 2022
Porting the example app from our Advanced iOS App Architecture book from UIKit to SwiftUI.

SwiftUI example app: Koober We're porting the example app from our Advanced iOS App Architecture book from UIKit to SwiftUI and we are sharing the cod

raywenderlich 55 Dec 19, 2022
SwiftUI iOS Widget and WatchOS app that randomly shows a word of the day with description and example.

Word Of The Day iOS Widget and WatchOS app made in SwiftUI that displays a random word of the day with description and example of usuage. Requirements

Kyle Dold 53 Nov 29, 2022
A curated list of Open Source example iOS apps developed in Swift

Example iOS Apps A curated list of Open Source example iOS apps developed in Swift. How to Use Example-iOS-Apps is an amazing list for people who are

null 1 Dec 15, 2021
An example to-do list app using SwiftUI which is introduced in WWDC19

SwiftUITodo SwiftUITodo is an example to-do list application using SwiftUI which is first introduced in WWDC19 keynote. Requirements Xcode 11 Beta Swi

Suyeol Jeon 701 Dec 23, 2022
SwiftUI and Combine based GitHubSearch example.

GitHubSearchWithSwiftUI GitHubSearchWithSwiftUI is an example that using Combine and SwiftUI Receive Results Receive Error SafariViewController ricemi

Taiki Suzuki 200 Dec 18, 2022
An example of creating custom popups in SwiftUI

Custom Popup Example An example project for Implementing custom popups in SwiftUI article. Author Artem Novichkov, [email protected] License The

Artem Novichkov 37 Dec 10, 2022
An example APOD app with SwiftUI and Combine using NASA API

SwiftUI-APOD An example Astronomy Picture of the Day(APOD) application using SwiftUI and Combine under iOS 13 Requirement Xcode 11 macOS 10.15 Catalin

Liang Yi 22 Oct 16, 2022
This is an example project of SwiftUI and Combine using GitHub API.

SwiftUI-Combine-Example This is an example project of SwiftUI and Combine using GitHub GET /search/users API. ?? Requirements Swift5.1 Beta Xcode11.0

Ryo Aoyama 436 Jan 5, 2023
An example of using SwiftUI + CoreData

ShoppingList An example of using SwiftUI + CoreData Screenshots ||| Running Must use the latest Xcode 11 beta, and be running some sort of beta softwa

Eric Lewis 12 Feb 11, 2022