---
title: Audience Activations with Ninetailed
slug: audience-activations-with-ninetailed
docTags: 
createdAt: 2025-06-04T15:56:48.731Z
---

# Introduction

This document provides an overview of how to use our Ninetailed Sync using Chord's Audiences API. Ninetailed is a personalization and experimentation platform built for modern, headless CMS and e-commerce setups. It enables marketers and developers to deliver tailored content and experiences to different user segments.

The primary focus when it comes to audience activations with Ninetailed via Chord is to add profile traits defined through Chord’s pre-built and custom audience dashboards. This enables real-time personalization by delivering dynamic audience data to Ninetailed.

:::hint{type="info"}
If you get stuck or have additional questions as you review this documentation, feel free to reach out to us at [help@chord.co](mailto\:help@chord.co) — our team is also happy to help you activate audiences on other CMS tools or platforms that help you get your job done!
:::

# Chord to Ninetailed Activation Flow

- **Chord Platform Application:** Audiences are created via the Chord platform per the existing flow.
- **Integration with DynamoDB:** Chord extracts Audience data from our Snowflake warehouses and stores it in an **AWS DynamoDB table**.
- **DynamoDB Stream:** A stream of events generated form changes to the table are queued.
- **AWS Lambda Function:** An **AWS Lambda function** receives the events via a connected stream trigger to process and bulk send up to 50 “identify” events per request.
  - If emails are used as the primary key for an audience, the emails are hashed before being sent as the id to Ninetailed.
- **Conentful/Ninetailed**: The synchronized traits can now be utilized in building targeted content using the trait attributes on the profile.

# Sample Request to Ninetailed

:::hint{type="info"}
Chord requires the following two items to setup the sync to the [bulk upsert URL](https://www.contentful.com/developers/docs/personalization/experience-api/#batch-upsert-profiles):

- **api\_key**
- **environment**
:::

```javascript
curl --location 'https://experience.ninetailed.co/v2/organizations/{API_KEY}/environments/{ENV}/events' \
--header 'Content-Type: application/json' \
--data '{
    "events": [
        {
            "channel": "server",
            "context": {
                "library": {
                    "name": "Chord Audiences",
                    "version": "1.0.0"
                }
            },
            "messageId": "58f358f2-a858-11ed-afa1-0242ac120002",
            "anonymousId": "(userId || anonymousId)",
            "userId": "(userId || anonymousId)",
            "traits": {"Audience - FirstTimeBuyer": "true" },
            "type": "identify"
        },
        {
            "channel": "server",
            "context": {
                "library": {
                    "name": "Chord Audiences",
                    "version": "1.0.0"
                }
            },
            "messageId": "58f358f2-a858-11ed-afa1-0242ac120002",
            "anonymousId": "(userId || anonymousId)",
            "userId": "(userId || anonymousId)",
            "traits": {"Audience - SuperFan": "false" },
            "type": "identify"
        }
    ]
}'
```

If emails are used as the primary key for an audience, the emails are hashed before being sent as the ID. If you would like to fetch the profile through Ninetailed using the email, you can obtain the id through this code snippet:

```jsx
async function hashEmail(email) {
	const encoder = new TextEncoder();
	const data = encoder.encode(email.toLowerCase());
	const hashBuffer = await crypto.subtle.digest('SHA-256', data);
	const hashArray = Array.from(new Uint8Array(hashBuffer));
	const base64Hash = btoa(String.fromCharCode(...hashArray));
	return base64Hash.replace(/[^a-zA-Z0-9]/g, '').substring(0, 32);
}
```

# DynamoDB Destination

Chord will handle the connection to the DynamoDB destination for you. You can view it as part of your [Data Activations](https://docs.chord.co/data-activations):&#x20;

![](https://api.archbee.com/api/optimize/VPxpEoMPxDsnmxOyjOdWV-GSUPCD0jzNGoCxiv5gAFW-20250604-160005.png)

# Creating a Sync

Using our Sync UI, we first need to create a new sync that connects a custom Audience as the **source** and our DynamoDB table as the **destination**.&#x20;

As a Chord tenant, you will have access to your own dedicated DynamoDB table. The example below is using `chord_audiences` for documentation purposes.

![](https://api.archbee.com/api/optimize/VPxpEoMPxDsnmxOyjOdWV-IIBTNPUc8q9wVFWASXs9f-20250604-160053.png)

## Select Sync Behavior

Sync Behaviors dictate the types of change that should be applied to your data when a sync finds a matching (or not) record in a source and a destination.

Available sync behaviors are:

- **Update or Create (aka Upsert):** Update existing destination records when IDs match, otherwise, create new records if they're missing.
- **Mirror:** Keep the destination in sync with the source.
  - If a row is added or edited in the source, update the destination.
  - If a previously synced row no longer is in the source, remove the matching object from the destination.

:::hint{type="info"}
Mirror syncs identify changes by comparing against the data they have already sent -- not the data that might or might not already exist in the destination.&#x20;

This means that the first sync will be an upsert for all records, and the second and following syncs will account for changes from the source data.
:::

![](https://api.archbee.com/api/optimize/VPxpEoMPxDsnmxOyjOdWV-HWRhV1evYyi9ZT8Iia6mH-20250604-160243.png)

# Sync Key

:::hint{type="danger"}
**Note:&#x20;**&#x54;he following steps (Sync Key, Field Mapping) are more advanced and should be handled by Chord employees or individuals with a strong understanding of the feature.
:::

Sync Keys will dictate how to associate data in the source with the destination. Both the source and destination need to provide a single, unique per record, identifying field. The identifiers will be used to look for matches. When a match is found - or not found - we then can use your selected Sync Behavior to decide what to do.&#x20;

Your sync key can be any kind of unique identifier, like a user ID, an email address, etc. However, we do recommend using a “blended user ID” provided by Chord if possible (see below).

## Mapping with a blended user identifier

Some audiences may contain what we call a “blended user ID,” which is derived from the Chord data models to contain the CDP User ID - if one exists - else the Anonymous ID. This use case is particularly useful when mixing users that may or may not have a known CDP User ID.

This means that you will be able to look up a user via the Audience API using either a CDP anonymous ID or a known User ID (in this case).

:::hint{type="info"}
When using blended ID, it is very important to keep in mind that if you query an Anonymous ID that was identified at any point, our API won't return any result.
:::

# Field Mapping

Once you've defined *how* data is related between your source and destination, the next step is to determine *what* properties should be updated. The field mapping step lets you specify how fields should be mapped from your source model to the destination object's fields.

- We start by assigning our unique user identifier. `anonymous_current_cdp_blended_user_id` will become our `pk` (primary key).
- We can then set up the `sk` (sort key). It is **important** to ensure that this value reflects the name of the Audience being synced. You can easily obtain that value by choosing `Sync Metadata > Source Name`

![](https://api.archbee.com/api/optimize/VPxpEoMPxDsnmxOyjOdWV-l-DPlQsNVCkMdTHP09kVw-20250604-184828.png)

You should end up with the following:

![](https://api.archbee.com/api/optimize/VPxpEoMPxDsnmxOyjOdWV-k8QyJ3A0yWvduWyPeXSWC-20250604-184854.png)

# Sync Schedule

Like any [Data Activations sync](https://docs.chord.co/gFnF-data-activations) on the Chord data platform, the Ninetailed sync can be scheduled to run at regular intervals.&#x20;

The Chord platform will display the sync results on th&#x65;**&#x20;Data Activations** page when you click into the **"Manage Syncs"** button.&#x20;

![](https://api.archbee.com/api/optimize/VPxpEoMPxDsnmxOyjOdWV-fuAQWG0ucAxMkBZweRVhS-20250604-184943.png "Sync Schedule Dropdown")

![](https://api.archbee.com/api/optimize/VPxpEoMPxDsnmxOyjOdWV-E3YejzY7wz1A8fcHZAkri-20250604-185856.png)

![](https://api.archbee.com/api/optimize/VPxpEoMPxDsnmxOyjOdWV-QZ2bv9iaWkdE7_QQEwX_6-20250604-190014.png "My Syncs sidesheet ")

