| Time | Status | User Agent | |
|---|---|---|---|
Retrieving recent requests… | |||
The Validate Request API checks incoming traffic against DataDome's
bot detection engine. Your integration sends request metadata to DataDome, and we return a decision: allow or challenge.
DataDome API should be requested by a component of your backend infrastructure (CDN, load balancer, application server, etc).
Protection API (custom integration) is only available for Premium and Enterprise customer.
Pre-requisites to implement API Integration
External API Communication
- The component must support synchronous HTTPS calls to external APIs.
HTTP Request Analysis
- Ability to read and process all HTTP request headers.
- Ability to access the end user’s IP address.
- [Recommended] Ability to collect TLS JA3 and JA4 fingerprints from incoming requests.
Request Management
- Configurable HTTP request timeout with a fail-open mechanism to maintain service continuity.
- Ability to exclude static assets (e.g., .css, .js, .jpg, etc.) from DataDome processing.
Response Handling
- Ability to dynamically inject custom headers into HTTP responses (e.g.,
Set-Cookie: datadome=xxxxxxxx). - Ability to store and forward data from the DataDome HTTP response to the final client response.
- Ability to return custom HTTP responses (html or json) with specific status codes (e.g., 401, 403, etc.) based on DataDome feedback.
Handling API response status code and body
The DataDome response is dynamic. It tells the integration what decision to enforce and how to update the request/response headers.
1. Integrity Validation
Before processing the response, you must verify that the HTTP status code of the API response matches the value in the X-DataDomeResponse header.
- If the values match: Proceed to the Response Logic below.
- If the values do NOT match: Ignore the API response and allow the request to proceed to your application (Fail-open).
2. Response Logic
Once the response is validated, the module must behave based on the X-DataDomeResponse header returned:
| Action | Status Codes | Logic to Follow |
|---|---|---|
| Allow | 200 | Pass the request Forward the request (with mapped upstream headers) to your backend server. |
| Challenge | 301, 302, 401, 403, 429 | Challenge the request Immediately return the DataDome API response (status code + body + mapped downstream headers) to the client. Do not contact your backend server. |
| Fail-open | All others | Ignore the error Treat the request as allowed (200) to avoid blocking legitimate traffic due to system errors. |
3. Handling API response headers
The DataDome API response contains instructions on how to modify both the upstream request (sent to your origin) and the downstream response (sent to the user). This must be done for both Allow and challenge status codes.
Universal Header Mapping
The API uses "Pointer Headers" to tell your module which specific headers to extract and where to move them. It is Mandatory for allow and challenge status codes.
| Pointer Header | Purpose | Action Required |
|---|---|---|
| X-DataDome-request-headers | Upstream Map | Lists headers in the API response that you must add to the request reaching your backend. |
| X-DataDome-headers | Downstream Map | Lists headers in the API response that you must add to the response reaching the browser. |
Security Guardrail: Never forward the "Pointer Headers" themselves (or any header listed inside them) back to the end-user. They are for your module's internal logic only.
Implementation Workflow
To process headers correctly, follow these two steps:
Step A: Update the Request (To Origin)
Check the value of X-DataDome-request-headers. It contains a space-separated list of header names. Extract these from the API response and inject them into the request before it hits your application. This feature is called Enriched headers
Step B: Update the Response (To User)
Check the value of X-DataDome-headers. Extract these from the API response and add them to the final response sent to the browser.
Practical Example
If the DataDome API response looks like this:
X-DataDome-request-headers: X-DataDome-isbot
X-DataDome-isbot: 1
X-DataDome-headers: Set-Cookie X-DD-B
Set-Cookie: datadome=ah78
X-DD-B: 1The module's execution:
- To your Application: Add the header
X-DataDome-isbot: 1. - To the User: Add the headers
Set-Cookie: datadome=ah78andX-DD-B: 1. - Here is an example of response headers sent by the API:
X-DataDome-request-headers: X-DataDome-botname X-DataDome-botfamily X-DataDome-isbot
X-DataDome-botname: Crawler fake Google
X-DataDome-botfamily: bad_bot
X-DataDome-isbot: 1
X-DataDome-headers: Set-Cookie Pragma X-DataDome Cache-Control
Set-Cookie: datadome=some-value; Domain=domain.com; Path=/; Expires=Wed, 13 Jan 2021 22:23:01 GMT;
Pragma: no-cache
X-DataDome: protected
Cache-Control: no-cache
X-DataDomeResponse: 403Functional requirements
Identifying the ClientID
The ClientIDis a mandatory field for the Protection API. It helps us to track the user session. Its source varies depending on whether the user is a standard web visitor or a client using Session by Header.
Extraction Logic
The module must check for the presence of the X-DataDome-ClientID header before falling back to the standard cookie.
| Source Priority | Location | Condition |
|---|---|---|
| Priority 1 | X-DataDome-ClientID Header | If this header is present in the incoming request. |
| Priority 2 | datadome Cookie value | If the custom header above is missing. |
- If an incoming HTTP request includes a
X-DataDome-ClientIDheader, its value should be picked for theClientIDfield instead of thedatadomecookie.
Implementation Requirements
When you extract the ID from the Priority 1 (Header) source, you must also signal to DataDome that you are expecting a custom cookie response format:
- Request Field: Map the extracted value to the ClientID field in your API payload.
- Response Signal: You must add the header
X-DataDome-X-Set-Cookie: trueto the request sent to DataDome's Protection API.
Expected Result: DataDome will return the new cookie value in the X-Set-Cookie header instead of the standard Set-Cookie (You don't need to handle this case. It will be handled out of the box though headers management).
Implementation Example (Lua)
This logic ensures the correct ID is sent and the system knows how to handle the session update.
if request_headers['x-datadome-clientid'] ~= nil then
body['ClientID'] = request_headers['x-datadome-clientid']
datadomeHeaders["X-DataDome-X-Set-Cookie"] = "true"
else
body['ClientID'] = clientId
endSequential diagram of the full flow

Payload Formatting & Constraints
- Encoding: All values must be URL encoded.
- Header Handling: Exclude fields for empty headers.
- Size & Truncation: To stay within the global 24 kB limit, truncate fields as listed below.
- Reverse truncation : Fields with an asterisk (*) are truncated from the end.
| Fields | Limit per field (in bytes) |
|---|---|
| Key, APIConnectionState, AuthorizationLen, CookiesLen, IP, Method, ModuleVersion, Port, PostParamLen, Protocol, RequestModuleName, TimeRequest | Unlimited |
| JsonRpcVersion, SecCHDeviceMemory, SecCHUAMobile, SecFetchUser | 8 |
| McpParamsClientInfoVersion, McpProtocolVersion, SecCHUAArch | 16 |
| SecCHUAPlatform, SecFetchDest, SecFetchMode | 32 |
| ContentType, JsonRpcRequestId, McpMethod, McpParamsClientInfoName, McpParamsToolName, McpSessionId, SecFetchSite | 64 |
| AcceptCharset, AcceptEncoding, CacheControl, Connection, From, GraphQLOperationName, Pragma, SecCHUA, SecCHUAModel, TrueClientIP, UserID, X-Real-IP, X-Requested-With, ProductId | 128 |
| AcceptLanguage, SecCHUAFullVersionList, Via | 256 |
| Accept, ClientID, HeadersList, Host, Origin, ServerHostname, ServerName, Signature, SignatureAgent, XForwardedForIP* | 512 |
| UserAgent | 768 |
| CookiesList, Referer | 1024 |
| Request, SignatureInput | 2048 |
