# Customer.io Destination Config Reference

<p><a href="https://www.rudderstack.com/docs/destinations/streaming-destinations/customer-io/setup-guide/" >Customer.io</a> is a messaging and marketing automation destination. RudderStack sends events to Customer.io&rsquo;s APIs from its servers, or through Customer.io&rsquo;s own SDKs in device mode on web, Android, and iOS.</p>
<p>In a Customer.io destination spec:</p>
<ul>
<li><code>type: customerio</code></li>
<li><code>definition_version: 1</code></li>
</ul>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="sample-configuration">Sample configuration</h2><div class="rs-code">
  <div class="rs-code__head">yaml<button class="rs-code__copy" type="button">
      
      Copy
    </button>
  </div>
  <div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: destination
metadata:
  name: customerio-prod
spec:
  id: customerio-prod
  display_name: Customer.io Production
  type: customerio
  definition_version: 1
  enabled: true
  config:
    site_id: &#34;{{ .CUSTOMERIO_SITE_ID }}&#34;
    api_key: &#34;{{ .CUSTOMERIO_API_KEY }}&#34;
    datacenter: US
    api_version: v2
    user_id_identifier_type: id
    device_token_event_name: Device Token Registered

    send_page_name_in_sdk:
      web: true
    data_use_in_app:
      web: false
    auto_track_device_attributes:
      android: true
      ios: true
    background_queue_min_number_of_tasks:
      android: &#34;10&#34;
    background_queue_seconds_delay:
      android: &#34;30&#34;

    connection_mode:
      web: device
      android: device
      cloud: cloud
    consent_management:
      web:
        - provider: oneTrust
          consents:
            - marketing</code></pre></div>
</div>
<p>The above example sends server-side events through the v2 API, and connects web and Android sources in <code>device</code> mode, where the SDK settings apply — see <a href="#device-mode" >Device mode</a>.</p>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="config-keys">Config keys</h2><p><code>config</code> accepts only the keys listed below. The <a href="https://www.rudderstack.com/docs/dev-tools/rudder-cli/destination-types/#config-key-rules" >shared config key rules</a> cover unknown keys, defaults, and immutability.</p>
<!-- end-chunk -->
<!-- begin-chunk -->
<h3 id="connection">Connection</h3><div class="rs-ckeys">
<div class="rs-ckey" id="site_id">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">site_id</p>RequiredSecret</div>
  <p class="rs-ckey__field">
    Type:
    <code>string</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Your Customer.io site ID.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li>At most 100 characters, and must not contain line breaks.</li>
<li>A <code>{{ path || fallback }}</code> template is accepted in place of a literal.</li>
</ul>

</div>

<div class="rs-ckey__extra">
  See <a href="https://www.rudderstack.com/docs/destinations/streaming-destinations/customer-io/setup-guide/#where-can-i-find-the-customerio-api-key-and-site-id" >Where can I find the Customer.io API key and site ID?</a>.
</div>

</div>

<div class="rs-ckey" id="api_key">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">api_key</p>RequiredSecret</div>
  <p class="rs-ckey__field">
    Type:
    <code>string</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Your Customer.io API key, paired with <code>site_id</code>.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li>At most 100 characters, and must not contain line breaks.</li>
<li>A <code>{{ path || fallback }}</code> template is accepted in place of a literal.</li>
</ul>

</div>

<div class="rs-ckey__extra">
  Supply it as a <code>{{ .VAR }}</code> reference rather than a literal — see <a href="#secrets" >Secrets</a>.
</div>

</div>

<div class="rs-ckey" id="datacenter">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">datacenter</p>Required</div>
  <p class="rs-ckey__field">
    Type:
    <code>string</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Region of your Customer.io account.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li><code>US</code> or <code>EU</code>.</li>
<li>The dashboard defaults this field to <code>US</code>. Rudder CLI requires it explicitly.</li>
<li>A spec that omits this key fails validation.</li>
</ul>

</div>

</div>

<div class="rs-ckey" id="device_token_event_name">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">device_token_event_name</p></div>
  <p class="rs-ckey__field">
    Type:
    <code>string</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Name of the event your app fires right after it sets the device token, so RudderStack can send the token to Customer.io immediately. Applies in both modes.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li>At most 100 characters, and must not contain line breaks.</li>
<li>A <code>{{ path || fallback }}</code> template is accepted in place of a literal.</li>
</ul>

</div>

</div>

</div>

<!-- end-chunk -->
<!-- begin-chunk -->
<h3 id="cloud-mode">Cloud mode</h3><p>These keys apply to events sent in <code>cloud</code> mode. They have no effect on device-mode delivery.</p>
<div class="rs-ckeys">
<div class="rs-ckey" id="api_version">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">api_version</p></div>
  <p class="rs-ckey__field">
    Type:
    <code>string</code>
  </p><p class="rs-ckey__field">
    Default value:
    <code>v2</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Customer.io API that delivers cloud-mode events.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li><code>v2</code> — Customer.io&rsquo;s unified <a href="https://docs.customer.io/integrations/api/track/tag/track_v2/batch/" >batch API</a>. Needs <code>user_id_identifier_type</code>.</li>
<li><code>v1</code> — Customer.io&rsquo;s per-endpoint APIs.</li>
<li>Omitting this key is the same as setting <code>v2</code>.</li>
</ul>

</div>

</div>

<div class="rs-ckey" id="user_id_identifier_type">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">user_id_identifier_type</p>Required</div>
  <p class="rs-ckey__field">
    Type:
    <code>string</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Customer.io identifier that receives the RudderStack <code>userId</code>.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li>Required when <code>api_version</code> is <code>v2</code> — including when you omit <code>api_version</code>, since <code>v2</code> is the default. Leave it unset only with <code>v1</code>.</li>
<li>One of <code>id</code>, <code>email</code>, <code>phone</code>, or <code>cio_id</code>. With <code>phone</code>, the value must read as E.164 — for example <code>+15551234567</code>.</li>
</ul>

</div>

<div class="rs-ckey__extra">
  <blockquote class="warning">
  <div class="tip-quote">
    
    <div class="tip-text"><code>userId</code> is sent as this identifier for every event, with no fallback — choose <code>id</code> and send an email address, and it&rsquo;s sent as an ID. A wrong choice attaches events to the wrong profiles or creates new ones, and that can&rsquo;t be reversed. With <code>v2</code>, events without a <code>userId</code> fail.</div>
  </div>
</blockquote>

</div>

</div>

</div>

<!-- end-chunk -->
<!-- begin-chunk -->
<h3 id="device-mode">Device mode</h3><p>These keys configure Customer.io&rsquo;s SDKs, so they apply only to sources connected in <code>device</code> mode. Each is keyed by the source type it applies to.</p>
<div class="rs-ckeys">
<div class="rs-ckey" id="send_page_name_in_sdk">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">send_page_name_in_sdk</p></div>
  <p class="rs-ckey__field">
    Type:
    <code>object</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Send the <code>page</code> name to Customer.io. When <code>false</code>, Customer.io records the page URL instead.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li><code>web</code> — boolean. The dashboard defaults it to <code>true</code>; Rudder CLI doesn&rsquo;t fill it in.</li>
</ul>

</div>

</div>

<div class="rs-ckey" id="data_use_in_app">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">data_use_in_app</p></div>
  <p class="rs-ckey__field">
    Type:
    <code>object</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Enable Customer.io <a href="https://customer.io/docs/journeys/in-app-getting-started/#javascript-snippet" >in-app messages</a> on your website.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li><code>web</code> — boolean. The dashboard defaults it to <code>false</code>.</li>
</ul>

</div>

</div>

<div class="rs-ckey" id="auto_track_device_attributes">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">auto_track_device_attributes</p></div>
  <p class="rs-ckey__field">
    Type:
    <code>object</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Let Customer.io&rsquo;s mobile SDK track device attributes automatically. Set <code>false</code> to track them yourself.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li><code>android</code>, <code>ios</code> — booleans. The dashboard defaults both to <code>true</code>; Rudder CLI doesn&rsquo;t fill them in.</li>
</ul>

</div>

<div class="rs-ckey__extra">
  <div class="rs-code">
  <div class="rs-code__head">yaml<button class="rs-code__copy" type="button">
      
      Copy
    </button>
  </div>
  <div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">auto_track_device_attributes:
  android: true
  ios: false</code></pre></div>
</div>

</div>

</div>

<div class="rs-ckey" id="background_queue_min_number_of_tasks">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">background_queue_min_number_of_tasks</p></div>
  <p class="rs-ckey__field">
    Type:
    <code>object</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Minimum number of tasks the Android SDK keeps in its background queue.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li><code>android</code> — a whole number written as a string, <code>&quot;10&quot;</code> rather than <code>10</code>. At most 100 characters, or a template.</li>
<li>The dashboard defaults it to <code>&quot;10&quot;</code>; Rudder CLI doesn&rsquo;t fill it in.</li>
</ul>

</div>

</div>

<div class="rs-ckey" id="background_queue_seconds_delay">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">background_queue_seconds_delay</p></div>
  <p class="rs-ckey__field">
    Type:
    <code>object</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Delay, in seconds, that the Android SDK holds events in its background queue.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li><code>android</code> — a whole number written as a string, <code>&quot;30&quot;</code> rather than <code>30</code>. At most 100 characters, or a template.</li>
<li>The dashboard defaults it to <code>&quot;30&quot;</code>; Rudder CLI doesn&rsquo;t fill it in.</li>
</ul>

</div>

</div>

</div>

<!-- end-chunk -->
<!-- begin-chunk -->
<h3 id="event-filtering">Event filtering</h3>
<blockquote class="warning">
  <div class="tip-quote">
    
    <div class="tip-text"><a href="https://www.rudderstack.com/docs/sources/event-streams/sdks/event-filtering/" >Client-side event filtering</a> applies only when <code>connection_mode.web</code> is <code>device</code> — the dashboard shows these controls only then, and the SDK is what applies the filter. Rudder CLI accepts the block in any mode, but it has no effect on other connections.</div>
  </div>
</blockquote>
<div class="rs-ckeys">
<div class="rs-ckey" id="event_filtering">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">event_filtering</p></div>
  <p class="rs-ckey__field">
    Type:
    <code>object</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Restricts which <code>track</code> events the web SDK passes to Customer.io, by event name.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li>Applies when <code>connection_mode.web</code> is <code>device</code>. Leave it unset otherwise.</li>
<li><code>whitelist</code> — array of event names to allow; every other <code>track</code> event is dropped.</li>
<li><code>blacklist</code> — array of event names to drop; every other <code>track</code> event is allowed.</li>
<li>The two are mutually exclusive, and Rudder CLI enforces it — setting both fails validation.</li>
<li>Each name is at most 100 characters, or a <code>{{ path || fallback }}</code> template.</li>
</ul>

</div>

</div>

</div>

<!-- end-chunk -->
<!-- begin-chunk -->
<h3 id="per-source-keys">Per-source keys</h3><p>Both keys are objects keyed by the local source type — the tokens listed under <a href="#source-types" >Source types</a>. A key naming a source type this destination doesn&rsquo;t support fails validation.</p>
<div class="rs-ckeys">
<div class="rs-ckey" id="connection_mode">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">connection_mode</p></div>
  <p class="rs-ckey__field">
    Type:
    <code>object</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Maps each source type you connect to the mode its events reach Customer.io in, using the modes in <a href="#source-types" >Source types</a>.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li>An entry is required for each source type you connect — see <a href="#connect-a-source" >Connect a source</a>.</li>
<li>A mode the source type doesn&rsquo;t support on this destination fails validation — for example <code>device</code> for <code>android_kotlin</code>.</li>
</ul>

</div>

<div class="rs-ckey__extra">
  <div class="rs-code">
  <div class="rs-code__head">yaml<button class="rs-code__copy" type="button">
      
      Copy
    </button>
  </div>
  <div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">connection_mode:
  web: device
  android: device
  ios: cloud</code></pre></div>
</div>

</div>

</div>

<div class="rs-ckey" id="consent_management">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">consent_management</p></div>
  <p class="rs-ckey__field">
    Type:
    <code>object</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Consent provider configuration per source type. The entry shape, accepted providers, and the rules on <code>resolution_strategy</code> and <code>consents</code> are shared across all destination types — see <a href="https://www.rudderstack.com/docs/dev-tools/rudder-cli/destination-types/#consent-management" >Consent management</a>.
</p>

</div>

</div>

<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="source-types">Source types</h2><p>Customer.io accepts events from these source types in the mentioned connection modes:</p>
<table>
<thead>
<tr>
<th>Source type</th>
<th>Connection mode</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>android</code></td>
<td><code>cloud</code>, <code>device</code></td>
</tr>
<tr>
<td><code>android_kotlin</code></td>
<td><code>cloud</code></td>
</tr>
<tr>
<td><code>ios</code></td>
<td><code>cloud</code>, <code>device</code></td>
</tr>
<tr>
<td><code>ios_swift</code></td>
<td><code>cloud</code></td>
</tr>
<tr>
<td><code>web</code></td>
<td><code>cloud</code>, <code>device</code></td>
</tr>
<tr>
<td><code>unity</code></td>
<td><code>cloud</code></td>
</tr>
<tr>
<td><code>cloud</code></td>
<td><code>cloud</code></td>
</tr>
<tr>
<td><code>react_native</code></td>
<td><code>cloud</code></td>
</tr>
<tr>
<td><code>flutter</code></td>
<td><code>cloud</code></td>
</tr>
<tr>
<td><code>cordova</code></td>
<td><code>cloud</code></td>
</tr>
</tbody>
</table>
<p><code>web</code>, <code>android</code>, and <code>ios</code> offer <code>device</code> mode. The Kotlin and Swift SDKs — <code>android_kotlin</code> and <code>ios_swift</code> — are <code>cloud</code> only. See <a href="https://www.rudderstack.com/docs/destinations/streaming-destinations/customer-io/device-mode/" >Customer.io device mode</a>.</p>

<html lang="en">
<blockquote class="info">
  <div class="tip-quote">
    
    <div class="tip-text">The dashboard additionally offers Customer.io to AMP, Shopify, and Reverse ETL sources. Rudder CLI doesn&rsquo;t manage those connections, so <code>amp</code>, <code>shopify</code>, and <code>warehouse</code> are invalid here.</div>
  </div>
</blockquote>

</html>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="connect-a-source">Connect a source</h2><p>An event stream connection to this destination is checked against two rules at <code>validate</code> time.</p>
<p><strong>The source&rsquo;s type must be supported.</strong> A source&rsquo;s type resolves to one of the tokens above before the check — a JavaScript source resolves to <code>web</code>, and webhook and server-side SDK sources resolve to <code>cloud</code>. An unsupported type reports:</p>
<div class="rs-code">
  <div class="rs-code__head"><button class="rs-code__copy" type="button">
      
      Copy
    </button>
  </div>
  <div class="highlight"><pre class="chroma"><code class="language-text" data-lang="text">destination &#39;customerio-prod&#39; (type &#39;customerio&#39;) does not support source &#39;my-source&#39;:
source type &#39;amp&#39; is not among supported source types: android, android_kotlin, ...</code></pre></div>
</div>
<p><strong>The destination config must carry a <code>connection_mode</code> entry for that source type.</strong> This lives on the destination spec, not on the <a href="https://www.rudderstack.com/docs/dev-tools/rudder-cli/yaml-connections/" >connection spec</a>. Without it:</p>
<div class="rs-code">
  <div class="rs-code__head"><button class="rs-code__copy" type="button">
      
      Copy
    </button>
  </div>
  <div class="highlight"><pre class="chroma"><code class="language-text" data-lang="text">destination &#39;customerio-prod&#39; config has no &#39;connection_mode&#39; entry for source type &#39;web&#39;</code></pre></div>
</div>
<p>Customer.io needs no additional config keys to connect a source of any type, in any mode.</p>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="secrets">Secrets</h2><p><code>api_key</code> and <code>site_id</code> are the secret keys. Write each as a <code>{{ .VAR }}</code> reference and supply the value at apply time:</p>
<div class="rs-code">
  <div class="rs-code__head">yaml<button class="rs-code__copy" type="button">
      
      Copy
    </button>
  </div>
  <div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">config:
  site_id: &#34;{{ .CUSTOMERIO_SITE_ID }}&#34;
  api_key: &#34;{{ .CUSTOMERIO_API_KEY }}&#34;</code></pre></div>
</div>
<div class="rs-code">
  <div class="rs-code__head">bash<button class="rs-code__copy" type="button">
      
      Copy
    </button>
  </div>
  <div class="highlight"><pre class="chroma"><code class="language-bash" data-lang="bash">export RUDDER_CUSTOMERIO_SITE_ID=&#34;...&#34;
export RUDDER_CUSTOMERIO_API_KEY=&#34;...&#34;
rudder-cli apply

# or
rudder-cli apply --var-file secrets.vars.yaml</code></pre></div>
</div>
<p>Note that:</p>
<ul>
<li>The YAML that <code>rudder-cli import</code> writes may or may not include secret keys. Before you apply, make sure every secret key your configuration needs is present and populated through variable substitution.</li>
<li>In web device mode the site ID is embedded in the page&rsquo;s JavaScript, so masking it protects your YAML, not the value itself.</li>
</ul>
<p>See <a href="https://www.rudderstack.com/docs/dev-tools/rudder-cli/variable-substitution/" >How to Use Variable Substitution in Rudder CLI</a>.</p>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="see-more">See more</h2><ul>
<li><a href="https://www.rudderstack.com/docs/destinations/streaming-destinations/customer-io/setup-guide/" >Customer.io Destination</a> for the API key and site ID, and the per-mode settings</li>
<li><a href="https://www.rudderstack.com/docs/dev-tools/rudder-cli/destination-types/" >Destination Type Reference for Rudder CLI</a> for the rules shared across destination types</li>
<li><a href="https://www.rudderstack.com/docs/dev-tools/rudder-cli/yaml-destinations/" >Destination YAML Reference</a> for the spec envelope</li>
</ul>

