iOS + Alamofire / Moya
How to integrate the DataDome SDK with Alamofire or Moya
Upgrading from 3.8.x or earlier?This guide covers a fresh v4 integration. For a step-by-step upgrade from a
v3.xversion, see the migration guide.
Still integrating an older version of this SDK?The
v3.xdocumentation has been moved to this page.
Requirements
- iOS 15.0+
- Xcode 16.0+ (the SDK is compiled in the Swift 6 language mode)
- Swift Package Manager only — CocoaPods support was removed in
4.0.0 - Alamofire 5.0.0+
- A DataDome client-side key, available in the DataDome Dashboard
Add the package
With Xcode
- In Xcode, open File ▸ Add Package Dependencies…
- Enter the package URL.
https://github.com/DataDome/datadome-alamofire-package.git - Set the dependency rule to Up to Next Major Version starting at
4.0.0. - Add the
DataDomeAlamofirelibrary product to your application target.
With a Package.swift manifest
Package.swift manifestdependencies: [
.package(url: "https://github.com/DataDome/datadome-alamofire-package.git", from: "4.0.0")
],
targets: [
.target(
name: "YourApp",
dependencies: [
.product(name: "DataDomeAlamofire", package: "datadome-alamofire-package")
]
)
]Configure your DataDome client-side key
You can provide your client-side key either programmatically or through your app's Info.plist.
Create the
DataDomeinstance once and reuse it for the lifetime of your app (for example, as a property of a shared networking object).
It is anactorand is safe to share across tasks.
Option A: Programmatic
import CoreDataDome
let configuration = DataDomeConfiguration(clientKey: "YOUR_CLIENT_SIDE_KEY")
let dataDome = DataDome(configuration: configuration)You can optionally pass a custom domain:
let configuration = DataDomeConfiguration(
clientKey: "YOUR_CLIENT_SIDE_KEY",
clientDomain: URL(string: "https://your-domain.com")
)Option B: Info.plist
Add a DataDome dictionary to your Info.plist:
<key>DataDome</key>
<dict>
<key>ClientSideKey</key>
<string>YOUR_CLIENT_SIDE_KEY</string>
<!-- Optional -->
<key>Domain</key>
<string>https://your-domain.com</string>
</dict>Then build the configuration from the bundle:
import CoreDataDome
let configuration = try DataDomeConfiguration.configurationFromBundle()
let dataDome = DataDome(configuration: configuration)
DataDomeConfiguration.configurationFromBundle()throws if theDataDomedictionary or itsClientSideKeyentry is missing.
Handle the error, or use the programmatic initializer instead.
Integrate with Alamofire
Create a DataDomeInterceptor from your DataDome instance and attach it to the requests you want to protect. DataDomeInterceptor conforms to Alamofire's RequestInterceptor, so you can pass it to either an individual request or the whole Session.
Per request
session.request(url, interceptor: interceptor)
.validate()
.responseData {
[...]
}Always call
.validate().
DataDome challenges are served as HTTP403responses. The interceptor only runs its validation logic when Alamofire reports the request as failed, so without.validate()a403would be handed back to your completion handler as a "success" and the challenge would never be presented or retried.
Per session
let session = Alamofire.Session(configuration: .default, interceptor: interceptor)Customizing the session
You are free to use your own Session and URLSessionConfiguration. If you do, keep the default cookie handling so the DataDome cookie set after a resolved challenge is attached to the retried request:
- Leave
configuration.httpShouldSetCookies = true(the default). - Keep the shared
HTTPCookieStorage(configuration.httpCookieStorage = .shared, the default).
Disabling cookie storage prevents the DataDome cookie from being sent on the retried request, so the request will be challenged again in a loop.
Troubleshooting
| Symptom | Resolution |
|---|---|
No such module 'CoreDataDome' | Make sure the DataDomeAlamofire product is added to your app target so SPM resolves CoreDataDome transitively. |
Crash on launch / configurationFromBundle() throws | The DataDome dictionary or its ClientSideKey entry is missing from Info.plist. Add it, or switch to the programmatic DataDomeConfiguration(clientKey:) initializer. |
| Challenges never appear / requests are never retried | Ensure the interceptor is attached to the request or session and that you call .validate() (or otherwise treat non-2xx responses as failures) so the 403 challenge is seen by the retrier. |
| Request keeps getting challenged in a loop | Cookie storage is disabled on your URLSessionConfiguration. Keep the default httpShouldSetCookies = true and the shared HTTPCookieStorage. |
pod install cannot find the pod | CocoaPods support was removed in 4.0.0. Integrate via Swift Package Manager. |
Cannot find type 'AlamofireInterceptor' / 'CaptchaDelegate' / 'DataDomeAdapter' | These were removed in 4.0.0. Use DataDomeInterceptor(dataDome:); challenge presentation is now automatic. |
Updated 4 days ago

