URLSession integration

How to use the DataDome SDK with URLSession

Version License Platform

Installation

Swift Package Manager

DataDomeSDK is available on Swift Package Manager. To get the SDK integrated in your project, follow the steps below:

  1. Go to "Xcode > File > Swift Packages > Add Package Dependency", select the target where to integrate DataDome
  2. Paste the following git URL in the search bar https://github.com/DataDome/datadome-ios-package
  3. Select DataDomeSDK and press Add

CocoaPods

DataDomeSDK is available on CocoaPods. Simply add the following line in your Podfile:

pod "DataDomeSDK"

Run pod install to download and integrate the framework into your project.

Carthage

DataDomeSDK is available on Carthage. To get the SDK integrated in your project, follow the steps below:

  1. Create a Cartfile if not already created.
  2. Add the following dependency in your project Cartfile
binary "https://raw.githubusercontent.com/DataDome/datadome-ios-package/refs/heads/master/DataDomeSDK.json" ~> 3.6.2
  1. Run the following command to fetch and integrate the package
carthage update --use-xcframeworks

Usage

Swizzling

The DataDomeSDK has an option to intercept all HTTP requests made from those URLSession methods:

  • func dataTask(with url: URL, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask
  • func dataTask(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask

We do that by swizzling, dynamically exchanging the implementation of those methods with our own.

Swizzling is activated by default, this means that if you wish to protect all of your HTTP request made by the above methods, you have nothing else to do.

Manually protecting requests

If you whish to handpick the HTTP requests you whish to protect, you will first need to deactivate the swizzling.
You can do that by adding this property to you project's info.plist

    <key>DataDomeProxyEnabled</key>
    <false/>

Then, to make a protected HTTP request, use one of the DataDomeSDK methods:

func protectedDataTask(with url: URL,
                       captchaDelegate: CaptchaDelegate?,
                       completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) 
                        -> URLSessionDataTask
func protectedDataTask(with request: URLSessionRequest,
                       captchaDelegate: CaptchaDelegate?,
                       completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) 
                        -> URLSessionDataTask
    func protectedDataTask(withURL url: URL, 
                           captchaDelegate: CaptchaDelegate?) async throws 
                            -> (Data, URLResponse)
    func protectedDataTask(withRequest request: URLRequest, 
                           captchaDelegate: CaptchaDelegate?) async throws 
                            -> (Data, URLResponse)

Combine

If you are using Combine and DataTaskPublisher to perform networking requests in your app, we have you covered.
Use the following apis to create a DataTaskPublisher with the DataDome operators

/// Provides a publisher with downstream DataDome operators
/// - Parameters:
///   - url: The url to be requested
///   - captchaDelegate: The captcha delegate
/// - Returns: A publisher with the DataDome operators
func protectedDataTaskPublisher(forURL url: URL,
                                captchaDelegate: CaptchaDelegate?)
    -> AnyPublisher<URLSession.DataTaskPublisher.Output, URLSession.DataTaskPublisher.Failure>

Or by using an URLRequest instance as parameter

/// Provides a publisher with downstream DataDome operators
/// - Parameters:
///   - request: The request to be processed
///   - captchaDelegate: The captcha delegate
/// - Returns: A publisher with the DataDome operators
func protectedDataTaskPublisher(forRequest request: URLRequest,
                                captchaDelegate: CaptchaDelegate?)
-> AnyPublisher<URLSession.DataTaskPublisher.Output, URLSession.DataTaskPublisher.Failure>

Here an example on how to use the DataDome protected publisher

import DataDomeSDK

URLSession
.shared
.protectedDataTaskPublisher(forURL: url, captchaDelegate: nil)
.sink(receiveCompletion: { completion in
      switch completion {
        case .finished:
            break
        case .failure(let error):
            print(error.localizedDescription)
      }
}, receiveValue: { response in
     guard let httpResponse = response.response as? HTTPURLResponse else {
       print("Invalid response")
       return
     }

     print("Did receive response with code \(httpResponse.statusCode)")
  }
})

You can use any other operators to validate or transform the publisher or part of its elements. For more details, please visit Apple Documentation

You can also implement the CaptchaDelegate protocol to manage the navigation of the CaptchaViewController

import DataDomeSDK

extension MyViewController: CaptchaDelegate {
    func present(captchaController controller: UIViewController) {
        self.navigationController?.present(controller, animated: true, completion: nil)
    }
    
    func dismiss(captchaController controller: UIViewController) {
        controller.dismiss(animated: true, completion: nil)
    }
}

More

SFCC support

When calling an SFCC endpoint, the captcha will be displayed according to different rules.

You will need to implement this method from the URLSessionTaskDelegate:
urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void)
And return nil if the URL inside the Location HTTP header has a path containing DDUser-Challenge as one of its components.

Example:

func urlSession(_ session: URLSession,
                task: URLSessionTask,
                willPerformHTTPRedirection response: HTTPURLResponse,
                newRequest request: URLRequest,
                completionHandler: @escaping (URLRequest?) -> Void) {
    if let location = response.value(forHTTPHeaderField: "location"),
        let url = URL(string: location),
        url.pathComponents.contains("DDUser-Challenge") {
        return completionHandler(nil)
    }

    return completionHandler(request)
}

🚧

On versions older than 3.6.0 only

You will also have to set DataDomeSDK.bypassHTTPAccept = true to display the captcha correctly.


What’s Next

Complete your integration by following the Configuration section on the main page