Data Import

Import your customer data into Data Activation to build richer profiles

Data Activation (formerly Customer Data Platform) lets you enrich customer profiles with data from external sources using the data import feature. With richer profiles, you can create more accurate audience segments, deliver better personalization, and improve your activations.

Ways to import data

There are two ways to import data:

Using webhook imports

This option accepts JSON payloads from any external tool, even when you don’t control the request format. You map the incoming fields to the Data Activation profile attributes in the UI. This method works well when importing data from services like email marketing tools, for example, updating subscriber status from MailChimp. Learn how to set it up in our help center guide.

Using API

This option requires data in a specific format but doesn’t involve any setup in the UI. It's a more advanced method, and works best when you control how data is sent, for example, when importing data directly from your app or custom code.

How to import data via API

You can import data to Data Activation with a single HTTP API request (API endpoint).

In the following example, we'll enrich a profile with order data:

POST /api/cdp/profiles/public/v1/app/{app_id}/update-profile

curl -X POST 'https://<example>/api/cdp/profiles/public/v1/app/<app_id>/update-profile' -H "Content-Type: application/json" --data '{
    "identifiers": {
        "cookie_id": "0123456789ABCDEF",
        "user_id": "[email protected]"
    },
    "attributes": {
        "analytics.order_time": "2025-05-23T09:37:27+01:00",
        "analytics.revenue": 500,
        "analytics.order_id": "UK/2025/05/65343"
    }
}'
await fetch('https://<example>/api/cdp/profiles/public/v1/app/<app_id>/update-profile', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    identifiers: {
      "cookie_id": "0123456789ABCDEF",
      "user_id": "[email protected]"
    },
    attributes: {
      "analytics.order_time": "2025-05-23T09:37:27+01:00",
      "analytics.revenue": 500,
      "analytics.order_id": "UK/2025/05/65343"
    }
  })
});
import requests

response = requests.post(
    'https://<example>/api/cdp/profiles/public/v1/app/<app_id>/update-profile',
    headers={'Content-Type': 'application/json'},
    json={
        'identifiers': {
            'cookie_id': '0123456789ABCDEF',
            'user_id': '[email protected]'
        },
        'attributes': {
            'analytics.order_time': '2025-05-23T09:37:27+01:00',
            'analytics.revenue': 500,
            'analytics.order_id': 'UK/2025/05/65343'
        }
    }
)

In your request, replace the placeholders with your own data:

  • <example> with your account address. Example: example.piwik.pro
  • <app_id> with your application ID
  • user_id and cookie_id with the actual user identifiers
  • attributes with your custom data you want to add to the profile

Request payload structure

The request payload always has two parts:

  • Identifiers - At least one ID that matches the profile (cookie ID, user ID, etc.). Learn more about identifiers in this guide.
  • Attributes - At least one attribute value you want to add or update. Learn more about profile attributes in this guide.

Verify your import

After importing your data, you can check if the profile was updated correctly. In the UI, go to Menu > Data Activation > People to see recently updated profiles, or use the API.

Get profile example

GET /api/cdp/profiles/v1/app/{app_id}/profile/{identifier_type}/{identifier_value}

::: info This endpoint requires an authorization token. Learn more on how to obtain and use the token in this guide. :::

curl -X GET 'https://<example>/api/cdp/profiles/v1/app/<app_id>/profile/user_id/[email protected]' -H "Authorization: Bearer <your_access_token>"

Response example

{
  "version": 1,
  "id": "43b5f062c57526ff",
  "app_id": "b8d3f43e-b36c-47a7-a018-f85e2caf0978",
  "created_at": "2025-09-09T20:56:30.310720845Z",
  "updated_at": "2025-09-09T21:23:31.821940Z",
  "identifiers": {
    "cookie_id": [
      "0123456789ABCDEF"
    ],
    "user_id": [
      "[email protected]"
    ]
  },
  "predefined_attributes": {
    "last_order_time": "2025-05-23T08:37:27Z",
    "total_revenue": 500
  },
  "custom_dimension_attributes": {},
  "custom_attributes": {}
}

A successful response will show the updated attributes.

Import data to custom attributes

In addition to predefined attributes, you can define custom attributes to capture data specific to your business.

First, you'll need to add a custom attribute with an event data key. Learn more about adding or editing a custom attribute in this guide. Then send data to it using the same API request format as for predefined attributes. For example, you might add custom fields like customer score, age, or favorite color.

Custom attributes example

curl -X POST 'https://<example>/api/cdp/profiles/public/v1/app/<app_id>/update-profile' -H "Content-Type: application/json" --data '{
    "identifiers": {
        "cookie_id": "0123456789ABCDEF",
        "user_id": "[email protected]"
    },
    "attributes": {
        "crm_user_score": 12,
        "age": 28,
        "favorite_color": "red",
        "sex": "female"
    }
}'
await fetch('https://<example>/api/cdp/profiles/public/v1/app/<app_id>/update-profile', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    identifiers: {
      cookie_id: '0123456789ABCDEF',
      user_id: '[email protected]'
    },
    attributes: {
      "crm_user_score": 12,
      "age": 28,
      "favorite_color": "red",
      "sex": "female"
    }
  })
});
import requests

response = requests.post(
    'https://<example>/api/cdp/profiles/public/v1/app/<app_id>/update-profile',
    headers={'Content-Type': 'application/json'},
    json={
        'identifiers': {
            'cookie_id': '0123456789ABCDEF',
            'user_id': '[email protected]'
        },
        'attributes': {
            'crm_user_score': 12,
            'age': 28,
            'favorite_color': 'red',
            'sex': 'female'
        }
    }
)

Q&A

Can I use this API from a browser?

Yes, the API supports CORS and can be called directly from browsers. This makes it perfect for Tag Manager implementations or client-side data collection.

Can I import data without authentication?

Yes, the API endpoint is public and works without authentication.

Can I import arrays or complex objects?

Webhook imports allow you to upload complex objects and choose in the UI which parts should be used for profile enrichment. This is perfect for importing data from external systems that send complex JSON structures.

API imports only support basic data types: strings, numbers, booleans, IPs, and date-time values.

How to format data for the import?

To format data for the import, use the following conventions for each data type:

  • String: Use plain text values. Example: "favorite_color": "red"

  • Number: Use integer or floating-point values without quotes. Example: "crm_user_score": 12 "analytics.revenue": 1.82

  • Boolean: Use true or false (without quotes). Example: "is_subscribed": true

  • Date-time: Use ISO 8601 format as a string. Example: "analytics.order_time": "2025-05-23T08:37:27Z"

  • IPv4 address: Use it as a string. Example: "analytics.location_ipv4": "192.168.1.1"

  • IPv6 address: Use it as a string. Example: "analytics.location_ipv6": "2001:0db8:85a3:0000:0000:8a2e:0370:7334"

What should I do if the import fails?

Check the response status code:

  • 400 Bad Request - Fix the request format or missing required fields
  • 402 Payment Required - CDP module is not enabled
  • 404 Not Found - Incorrect App ID
  • 422 Unprocessable Entity - Data validation failed

What happens when malformed data is sent to an attribute

When you send malformed data, the behavior depends on the import method:

Webhook imports:

  • The request is received and processed
  • Server responds with HTTP 202 (Accepted)
  • The entire update is rejected
  • Detailed error information is displayed in the UI

Update Profile API:

  • The request is immediately rejected
  • Server responds with HTTP 400 (Bad Request)
  • Response contains specific error details about what went wrong