# Migrate subscription preferences

You may have managed your audience’s subscription preferences manually—with your own attributes in a system outside of Customer.io. Before you use our subscription center feature, you probably want to migrate your audience’s preferences to the `cio_subscription_preferences` attribute so your audience’s preferences still apply when you enable the subscription center.

 These steps will not affect your audience’s global subscription status

This page is about migrating subscription preferences—the topics and channels a person wants (or does not want) to receive messages for. These steps will not affect your [audience’s `unsubscribed` attribute](/journeys/unsubscribes/)—which indicates whether a person has opted out of messages.

## How it works[](#how-it-works)

If you used to manage subscription preferences outside our subscription center feature, or you set up new “opt-in” topics or channels, you’ll want to apply people’s current preferences to the `cio_subscription_preferences` attribute.

This ensures that you continue to observe your audience’s preferences when you enable the subscription center feature in Customer.io.

To migrate your audience’s preferences, we’ll:

1.  Create a segment of people who have subscription preference attributes
2.  Use this segment as a campaign trigger
3.  In the campaign, use a *Create or Update Person* action to set current preferences as topics and channels in the `cio_subscription_preferences` object.

### The subscription preferences attribute[](#subscription-attribute)

You can set your audience’s subscription preferences using the reserved `cio_subscription_preferences` [attributeA key-value pair that you associate with a person or an object—like a person’s name, the date they were created in your workspace, or a company’s billing date etc. Use attributes to target people and personalize messages.](/journeys/attributes/). This attribute contains both `topics` and `channels` preferences where every individual preference is a boolean (true/false).

**Topics** are numbered based on the ID that you see in the UI—`topic_1` corresponds to ID 1 in the left-column in your Subscription Center setup page. We set subscription preferences by topic *ID* rather than the topic *Name*, so that you can change the name of a topic without affecting your audience’s preferences.

**Channels** use the channel type name as the key (`email`, `sms`, `push`, `in_app`, `whatsapp`, `slack`, `line`, `inbox`). Channel preferences let people opt in or out of specific messaging channels, independent of their topic preferences.

When you send a message, a person must be subscribed to **both** the relevant topic and channel to receive the message.

```json
{
   "cio_subscription_preferences": {
      "topics": {
         "topic_1": true,
         "topic_2": false
      },
      "channels": {
         "email": true,
         "sms": true,
         "push": false
      }
   }
}
```

[![Within Workspace Settings, this subscription center has a table with 5 topics. Each topic has an ID followed by a name and the default status, not subscribed or subscribed.](https://docs.customer.io/images/subscription-preferences-topic-id-2025.png)](#eb274f13f261e81433fe17b5bad9409e-lightbox)

## Migrate subscription preferences[](#migrate-subscription-preferences)

There are plenty of ways to map subscription preferences. In this case, we’re using a campaign, but you could also use our API, upload a CSV, etc.

Before you start this process, we recommend that you:

1.  [Create your topics and channels](/journeys/subscription-center/#add-topics)
2.  Apply topics to your [campaigns and broadcasts](/journeys/subscription-center/#set-a-topic-in-a-campaign-or-broadcast)
3.  Figure out all the places where you’ll need to update subscription preferences. If you let your audience set their subscription preferences when they sign up, or inside your mobile apps, etc, you’ll want to make sure that you update those places to use Customer.io’s subscription center attributes as well.

### Before you begin: relate preferences to topics and channels[](#before-you-begin-relate-preferences-to-topics-and-channels)

In Customer.io, we store topic preferences by number (incremental, beginning at `1`), so that changing the name of a topic doesn’t cause cascading changes to your audience. But that means that you’ll need to map your previous preference attributes to your new topic number.

So, if your attribute was previously called `basketball` and is now your first topic, you’ll map your audience’s `basketball` preference to `cio_subscription_preferences.topics.topic_1`.

Channel preferences use the channel type as the key—for example, `email`, `sms`, or `push`. If you previously tracked channel opt-outs with custom attributes (like `no_sms`), you’ll map those to `cio_subscription_preferences.channels.sms`.

### Create a segment[](#create-a-segment)

In this process, we assume that you previously stored your audience’s preferences as individual attributes, but the same basic process applies if you previously stored preferences as an object, array, etc.

1.  Go to **Segments** and click **Create Segment**.
2.  Set a *Name* and *Description* for your segment, and then click **Create Data-driven Segment**.
3.  Set up your campaign so ***At least one** of the following conditions match*. This ensures that people with any preference join your segment.
4.  Add conditions where each “preference” attribute *exists*.
5.  Click **Save Changes**.

Now you’re ready to set up a campaign to move your preference attributes to the new `cio_subscription_preferences` attribute.

[![set up a segment with your past subscription settings](https://docs.customer.io/images/subscription-migration-segment.png)](#60f00753c074b247b90de915a785999b-lightbox)

### Create your migration campaign[](#create-your-migration-campaign)

This is a very short campaign with one step that simply sets your audience’s preferences. We’ll use the [segmentA group of people who match a series of conditions. People enter and exit the segment automatically when they match or stop matching conditions.](/journeys/data-driven-segments/) that you created as the trigger. And then we’ll map your previous migration preferences to attributes.

1.  Go to **Campaigns** and click **Create Campaign**.
    
2.  Set a *Name* and *Description* for your campaign.
    
3.  Click **Choose trigger** then select **Attribute or Segment**.
    
4.  Select the [segment you created earlier](#create-a-segment). Click **Save**.
    
5.  In your workflow, add a **Create or Update Person** action, select it, and click **Add Details**.
    
6.  Set subscription preferences via JavaScript.
    
     Set and overwrite all preferences
    
    #### Set and overwrite all preferences[](#Set and overwrite all preferences)
    
    *   The **Attribute** is `cio_subscription_preferences`.
        
    *   The **Value** is *JavaScript*. Don’t worry [if you don’t know JavaScript](/journeys/js-in-actions/); we’ve provided an example below!
        
    *   In the final box, add JavaScript to map your data to the subscription preference attribute. In our example, we check if the baseball and basketball attributes exist. Since these attributes are boolean, we can map the value directly to the new subscription preference, if they exist; otherwise, we assume that a person isn’t subscribed to the corresponding topic (`false`). **Be sure to include mappings to all topics and channels because this method does NOT preserve existing preferences for unspecified items. Those would revert back to the default opt-in/out status.**
        
        ```javascript
          return {
              topics: {
                topic_1: customer.baseball ? customer.baseball : false,
                topic_2: customer.basketball ? customer.basketball : false
              },
              channels: {
                email: customer.wants_email !== false,
                sms: customer.wants_sms !== false,
                push: customer.wants_push !== false
              }
            }
        ```
        
    
     Set preferences and preserve others
    
    #### Set preferences and preserve others[](#Set preferences and preserve others)
    
    Add a line for each topic or channel you want to set:
    
    *   For topics, the **Attribute** is `cio_subscription_preferences.topics.topic_<id>` where id is the system-generated id for the topic name in the subscription center. For channels, use `cio_subscription_preferences.channels.<channel>` (for example, `cio_subscription_preferences.channels.email`).
        
    *   The **Value** is *JavaScript*.
        
    *   In the final box, enter JavaScript to return the preference value from an attribute or a default if the attribute doesn’t exist. **This method updates only the specified preferences and preserves existing preferences for unspecified topics and channels.**
        
        ```javascript
            return customer.<attribute_name> ?? <boolean>;
        ```
        
        [![set your audience's subscription attributes](https://docs.customer.io/images/subscription-migration-action-4.png)](#7534d50b011c5f61ddc3caa980af2215-lightbox)
        
    
7.  (Optional) Delete the attribute that you’re migrating from. After we apply the `baseball` attribute to `topic_<x>`, we probably don’t need to keep it around!
    
8.  After you’ve added all of your attributes, click **Save** and start your campaign.
    

## Update subscription preferences via the API[](#subscription-preferences-api)

For each person in your workspace, you can set subscription attributes using the `identify` action in our API. Your payload changes based on whether you use our [Pipelines](/integrations/api/cdp/#operation/identify) or [Track](/integrations/api/track/#operation/identify) APIs, but we’ve posted examples of both below.

To update some preferences while preserving others, use JSON dot notation: `"cio_subscription_preferences.topics.topic_<topic ID>":<boolean>` for topics or `"cio_subscription_preferences.channels.<channel>":<boolean>` for channels.

 Pipelines API (Recommended)

#### Pipelines API (Recommended)[](#Pipelines API \(Recommended\))

```json
https://cdp.customer.io/v1/identify

{
    "userId": "cool.person@example.com",
    "traits": {
        "cio_subscription_preferences": {
            "topics": {
                "topic_1": true
            },
            "channels": {
                "email": true,
                "sms": true,
                "push": false
            }
        }
    }
}
```

 Classic Track API identify

#### Classic Track API identify[](#Classic Track API identify)

```json
https://track.customer.io/api/v1/customers/cool.person@example.com

{
  "cio_subscription_preferences": {
    "topics": {
      "topic_1": true
    },
    "channels": {
      "email": true,
      "sms": true,
      "push": false
    }
  }
}
```

 You can also update in batches

The [Pipelines API](/integrations/api/cdp/#operation/batch) supports a `/batch` endpoint that lets you send changes for multiple people in a single request.

## Set subscription preferences using the web SDK[](#subscription-preferences-js)

If you use our [JavaScript SDK](/integrations/data-in/connections/javascript/) or [Classic JavaScript SDK](/integrations/data-in/connections/javascript/legacy-js/getting-started/) on your website, you can set subscription preferences with the `identify` function. You might want to do this if you let people set their subscription preferences as a part of your signup flow.

 JavaScript Source (Recommended)

#### JavaScript Source (Recommended)[](#JavaScript Source \(Recommended\))

```javascript
cioanalytics.identify('cool.person@example.com', {
  first_name: 'cool',
  last_name: 'person',
  cio_subscription_preferences: {
    topics: {
      topic_1: true,
      topic_2: false
    },
    channels: {
      email: true,
      sms: true,
      push: false
    }
  }
})
```

 Classic JavaScript SDK

#### Classic JavaScript SDK[](#Classic JavaScript SDK)

```javascript
_cio.identify({
  email: "cool.person@example.com",
  first_name: 'cool',
  last_name: 'person',
  cio_subscription_preferences: {
    "topics": {
      "topic_1": true,
      "topic_2": false
    },
    "channels": {
      "email": true,
      "sms": true,
      "push": false
    }
  }
})
```

## Upload subscription preferences via CSV[](#subscription-preferences-csv)

You can set some or all subscription topic preferences for people by importing a CSV in the [People tab](https://fly.customer.io/workspaces/last/journeys/people).

#### Set one or more topic preferences for a person[](#update-specific-prefs)

You can use this method to update any and all subscription preferences for people without overwriting preferences for topics not specified in the CSV.

Add each subscription center topic name you want to set as its own column header. Upon upload, you’ll map each header to the attribute `cio_subscription_preferences.topics.topic_<topic ID>` where the topic ID corresponds to the topic name. You can find this on your subscription center landing page or by retrieving subscription center topics in our App API.

[![An image of two tables. The table on the left has a header titled Product Updates. Under this are the boolean values being assigned to two users' preferences. At the bottom, the header is mapped to the attribute cio_subscription_preferences.topics.topic_1. The other table maps the header Marketing to topic 3.](https://docs.customer.io/images/subscription-center-csv-import-partial.png)](#4d73ca62d9b4dc205ba615676e141e6d-lightbox)

After you complete the import, you’ll see that only the topic preferences you specified in the CSV show changes on the person’s profile.

Before uploading, another option is to add a column header that already matches the JSON dot notation above. When you go to map fields, the correct attribute name automatically populates.

#### Set all topic preferences for a person[](#update-all-prefs)

You can use this method to update ALL topic preferences per person, not a selection of topic preferences.

 Include every topic and value per person

If you do not include all topic preferences for each person using this method, the person’s preferences that are not specified in the import will be overwritten to match the default opt-in/out status of the topic.

You can import subscription preferences for a person by adding a column header `cio_subscription_preferences` and including the same JSON structure that our API expects. The contents of this column are `topics` objects, as follows:

```fallback
email,first_name,cio_subscription_preferences
person@example.com,person,{"topics":{"topic_1":true,"topic_2":false}}
another.person@example.com,another,{"topics":{"topic_1":true,"topic_2":true}}
```

See this [spreadsheet](https://docs.google.com/spreadsheets/d/1zVgwD_9nYC4jXk9LMUaJJFXlTtKIEQQBbO6Gt489sBo/edit?usp=sharing) for an example.