**Last updated**: 22 April 2025 | [**Change log**](/access/products/3ds/changelog/)

# Device Data Collection (DDC)

The card issuer uses Device Data Collection (DDC) to fingerprint the customer's device.

Along with the risk data in the [authentication](/access/products/3ds/react-native/authentication) request, it's used to decide if a [challenge](/access/products/3ds/react-native/challenge-verification) is needed or if the authentication can be frictionless (no challenge displayed to your customer).

Important
Invoke this process immediately upon the customer providing their payment credentials. This ensures that DDC processes asynchronously behind the scenes, as the customer completes the remaining checkout process. If a customer changes their card number after the DDC process is started or completed, re-execute the entire DDC process.

## Device data initialization

`POST` your device data initialization request to the `3ds:deviceDataInitialize` action link.

This request creates a JSON Web Token (JWT) that is used as part of the DDC form. The DDC form also requires the first six digits of your customer's card number (BIN). The BIN can be returned if a token resource is provided, see `JWT + BIN (token)` request.

For consistency of integration you can also provide the full card number `JWT + BIN (card)`  or `JWT + BIN (Network Token)`. It will be truncated to become the BIN in the response.

### Device data initialization example request

JWT only
JWT + BIN (Token)
JWT + BIN (Card)
JWT + BIN (Network Token)
### Device data initialization response

Best practice
Access Worldpay returns a `WP-CorrelationId` in the headers of service responses. We **highly recommend** you log this. The `WP-CorrelationId` is used by us to examine individual service requests.

To understand what these outcomes mean and how to reproduce them for testing purposes see [3DS testing](/access/products/3ds/testing)

JWT + BIN returned
JWT and BIN returned

```json JWT and BIN returned
description: Initialize the device data collection using the card number, worldpay token or network token
value:
  {
      "outcome": "initialized",
      "transactionReference": "Memory265-13/08/1876",
      "deviceDataCollection": {
          "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJPcmdVbml0SWQiOiJPcmdVbml0IiwiaXNzIjoiYXBpSWQiLCJleHAiOjE1NjI5MjMzNDYsImlhdCI6MTU2MjkyMzQwNiwianRpIjoiYTAzMWVhOGEtN2E0Zi00YTQwLWI1NjMtOTUzMzYzMzVhZGNmIn0.0IK74OIXBxFsxqeOURJz1TFnz14ZTbFJTdTWo9cHUJQ",
          "url": "https://ddcUrl.example.com",
          "bin": "555555"
      },
      "_links": {
          "3ds:authenticate": {
              "href": "https://try.access.worldpay-bsh.securedataplatform.com/verifications/customers/3ds/authentication"
          },
          "curies": [
              {
                  "href": "https://try.access.worldpay-bsh.securedataplatform.com/rels/verifications/customers/3ds/{rel}",
                  "templated": true,
                  "name": "3ds"
              }
          ]
      }
  }
```

JWT only
Only JWT returned

```json Only JWT returned
description: Initialize the device data collection without a payment instrument. Only the JWT is returned. 
value:
  {
      "outcome": "initialized",
      "transactionReference": "Memory265-13/08/1876",
      "deviceDataCollection": {
          "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJPcmdVbml0SWQiOiJPcmdVbml0IiwiaXNzIjoiYXBpSWQiLCJleHAiOjE1NjI5MjMzNDYsImlhdCI6MTU2MjkyMzQwNiwianRpIjoiYTAzMWVhOGEtN2E0Zi00YTQwLWI1NjMtOTUzMzYzMzVhZGNmIn0.0IK74OIXBxFsxqeOURJz1TFnz14ZTbFJTdTWo9cHUJQ",
          "url": "https://ddcUrl.example.com"
      },
      "_links": {
          "3ds:authenticate": {
              "href": "https://try.access.worldpay-bsh.securedataplatform.com/verifications/customers/3ds/authentication"
          },
          "curies": [
              {
                  "href": "https://try.access.worldpay-bsh.securedataplatform.com/rels/verifications/customers/3ds/{rel}",
                  "templated": true,
                  "name": "3ds"
              }
          ]
      }
  }
```

The `DeviceDataCollection` object is used for the next step.

Note
In case of an error, you can get further information in our [error reference](/access/products/reference/worldpay-error-responses).

## Device Data Collection (DDC)

The device data process for React Native uses:

- a hidden [WebView](https://github.com/react-native-webview/react-native-webview)
- an HTML page responsible for interfacing the HTML/JavaScript layer with the React Native layer
- an iframe, embedded in the HTML page
- a secondary HTML page, loaded via the iframe, and used to kickstart the DDC


1. Install and link the React Native `WebView` component in your application



```bash
# 1. Install dependency
npm install react-native-webview

# 2. Link dependency using your preferred method
react-native link react-native-webview

# 3. Ee-install pods
cd ios
pod install
```

1. Add a hidden `WebView` in your React Native application with the source pointing to the HTML page created in the next step.
Add also an event listener for the `message` event which is used to catch messages sent from the HTML layer to the React Native layer.


React Native

```javascript React Native
<WebView
  source={{ uri: 'replace-this-with-the-url-of-the-html-page-that-wraps-the-iframe' }}
  onMessage={(event) => {
    // deserialising and extracting JSON data from the event
    console.info(JSON.parse(event.nativeEvent.data));
  }}
  containerStyle={{ position: 'absolute', width: 0, height: 0 }}
/>
```

1. Create and host the HTML page which is used to interface the HTML/JavaScript layer with the React Native layer.


HTML

```html HTML
<html lang="en">
<head></head>
<body>
</body>
</html>
```

1. Add a script to the HTML page to relay to the React Native layer messages received by `postMessage()` in the HTML page.


JavaScript

```javascript JavaScript
<script language="JavaScript">
window.onmessage = (event) => {
  // for Try: https://centinelapistag.cardinalcommerce.com
  // for Production: https://centinelapi.cardinalcommerce.com
  const allowedOrigin = '...';

  // Always verify that the message received is from the expected origin
  if (event.origin !== allowedOrigin) {
    return;
  }

  // the event data must be serialised into a string
  window.ReactNativeWebView.postMessage(JSON.stringify(event.data));
};
</script>
```

1. Add an iframe to the HTML page and set the `src` attribute to the URL of the page that POSTs the DDC form. This URL should contain the following query string parameters: `deviceDataCollection.jwt`, `deviceDataCollection.bin` and `deviceDataCollection.url`. Those are used in the DDC form.


HTML

```html HTML
<iframe src="replace-this-with-the-url-of-your-page-that-posts-the-ddc-form"></iframe>
```

1. Create and host the secondary HTML page that POSTs the DDC form.


HTML

```javascript HTML
<html>
<body>
<!-- Using your preferred programming language, set the 'action' attribute with the value of the query string parameter containing the 'deviceDataCollection.url' from the device data initialization response -->
<form id="collectionForm" name="devicedata" method="POST" action="https://ddcUrl.example.com">

    <!-- Using your preferred programming language, set the 'value' attribute with the value of the query string parameter containing the 'deviceDataCollection.bin' from the device data initialization response -->
    <input type="hidden" name="Bin" value="555555" />

    <!-- Using your preferred programming language, set the 'value' attribute with the value of the query string parameter containing the 'deviceDataCollection.jwt' from the device data initialization response -->
    <input type="hidden" name="JWT" value="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJPcmdVbml0SWQiOiJPcmdVbml0IiwiaXNzIjoiYXBpSWQiLCJleHAiOjE1NjI5MjMzNDYsImlhdCI6MTU2MjkyMzQwNiwianRpIjoiYTAzMWVhOGEtN2E0Zi00YTQwLWI1NjMtOTUzMzYzMzVhZGNmIn0.0IK74OIXBxFsxqeOURJz1TFnz14ZTbFJTdTWo9cHUJQ" />

</form>

<script>
  window.onload = function() {
    document.getElementById('collectionForm').submit();
  }
</script>
</body>
</html>
```

### Test device data form

The form below allows you to submit the 3DS device data details provided in the API response. You then receive the sessionId/collectionReference, back in the postMessage, for use in the [authentication](/access/products/3ds/react-native/authentication) request. This is useful if using tools such as postman/insomnia to test your integration.

Access 3ds - Device Data Collection form
### Device Data Collection postMessage

Once the DDC form is submitted and is successfully sent to the card issuer, you are notified via a [postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) event.

For security, verify the sender's identity using the postMessage `origin` property as detailed [here](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage).

| Environment | Origin |
|  --- | --- |
| Try | https://centinelapistag.cardinalcommerce.com |
| Production | https://centinelapi.cardinalcommerce.com |


An example postMessage response:

postmessage

```json postmessage
{
    "MessageType": "profile.completed",
    "SessionId": "0_3XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXX6b5",
    "Status": true
}
```

| Key | Value |
|  --- | --- |
| `messageType` | `profile.completed` |
| `SessionId` | UUID, not present or `undefined` |
| `Status` | `true` - Use the `SessionId` value in `deviceData.collectionReference` as part of the [Authentication request](/access/products/3ds/react-native/authentication)`false` -  `SessionId` is empty. Either retry DDC or send the authentication request without the `deviceData.collectionReference`. |


The DDC call typically takes 1-2 seconds. This depends on the latency between the customer's device, the Cardinal servers and, in part, the type of Device Data Collection performed by the different issuers. The 3DS specification has a maximum response time of 10 seconds.

Note
If no postMessage is provided either retry DDC or send the [authentication request](/access/products/3ds/react-native/authentication) without the `deviceData.collectionReference`. We **highly recommend** [providing device data](/access/products/3ds/react-native/authentication#how-much-data-to-provide) (e.g. browserScreenHeight) in the authentication request as well. This will maximize authentication rates in the case of DDC failure.

### Full integration example code

Dependency

```bash
# 1. Install dependency
npm install react-native-webview

# 2. Link dependency using your preferred method
react-native link react-native-webview

# 3. Ee-install pods
cd ios
pod install
```

React Native

```javascript
<WebView
  source={{ uri: 'replace-this-with-the-url-of-the-html-page-that-wraps-the-iframe' }}
  onMessage={(event) => {
    // deserialising and extracting JSON data from the event
    console.info(JSON.parse(event.nativeEvent.data));
  }}
  containerStyle={{ position: 'absolute', width: 0, height: 0 }}
/>
```

HTML page 1

```javascript
<html>
<body>
<script language="JavaScript">
  window.onmessage = (event) => {
    // for Try: https://centinelapistag.cardinalcommerce.com
    // for Production: https://centinelapi.cardinalcommerce.com
    const allowedOrigin = '...';

    // Always verify that the message received is from the expected origin
    if (event.origin !== allowedOrigin) {
      return;
    }

    // the event data must be serialised into a string
    window.ReactNativeWebView.postMessage(JSON.stringify(event.data));
  };
</script>

<iframe src="replace-this-with-the-url-of-your-page-that-posts-the-ddc-form"></iframe>
</body>
</html>
```

HTML page 2

```javascript
<html>
<body>
<!-- Using your preferred programming language, set the 'action' attribute with the value of the query string parameter containing the 'deviceDataCollection.url' from the device data initialization response -->
<form id="collectionForm" name="devicedata" method="POST" action="https://ddcUrl.example.com">

    <!-- Using your preferred programming language, set the 'value' attribute with the value of the query string parameter containing the 'deviceDataCollection.bin' from the device data initialization response -->
    <input type="hidden" name="Bin" value="555555" />

    <!-- Using your preferred programming language, set the 'value' attribute with the value of the query string parameter containing the 'deviceDataCollection.jwt' from the device data initialization response -->
    <input type="hidden" name="JWT" value="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJPcmdVbml0SWQiOiJPcmdVbml0IiwiaXNzIjoiYXBpSWQiLCJleHAiOjE1NjI5MjMzNDYsImlhdCI6MTU2MjkyMzQwNiwianRpIjoiYTAzMWVhOGEtN2E0Zi00YTQwLWI1NjMtOTUzMzYzMzVhZGNmIn0.0IK74OIXBxFsxqeOURJz1TFnz14ZTbFJTdTWo9cHUJQ" />

</form>

<script>
  window.onload = function() {
    document.getElementById('collectionForm').submit();
  }
</script>
</body>
</html>
```

**Next steps**

[Authentication](/access/products/3ds/react-native/authentication)