# Pushwoosh Cloud Mode Integration



<blockquote class="announcement">
  <div class="tip-quote">
    
    <div class="tip-text"><p>The Pushwoosh destination integration is maintained by the Pushwoosh team and is currently in <strong>Private Beta</strong>.</p>
<p>Reach out to <a href="mailto:support@rudderstack.com" >Customer Success</a> if you&rsquo;re interested in enabling this destination for your workspace.</p>
</div>
  </div>
</blockquote>

<p>Cloud mode sends <code>track</code> events to Pushwoosh as custom events and <code>identify</code> traits as user-specific tags.</p>
<p>Find the open source transformer code for this destination in the <a href="https://github.com/rudderlabs/rudder-transformer/tree/main/src/v0/destinations/pushwoosh" >GitHub repository</a>.</p>

<html lang="en">
<blockquote class="info">
  <div class="tip-quote">
    
    <div class="tip-text">Pushwoosh matches users by User ID. The Pushwoosh SDK in your app must call <code>setUserId</code> with the same value you send to RudderStack as <code>userId</code>. <code>userId</code> is required on every event; anonymous events can&rsquo;t be attributed in Pushwoosh.</div>
  </div>
</blockquote>

</html>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="identify">Identify</h2><p>An <code>identify</code> call sends traits as user-specific tags. See the <a href="https://www.rudderstack.com/docs/event-spec/standard-events/identify/" >Identify</a> event for the call format.</p>
<p>A sample <code>identify</code> call:</p>
<div class="rs-code">
  <div class="rs-code__head">javascript<button class="rs-code__copy" type="button">
      
      Copy
    </button>
  </div>
  <div class="highlight"><pre class="chroma"><code class="language-javascript" data-lang="javascript">rudderanalytics.identify(&#34;user-123&#34;, {
  plan: &#34;growth&#34;,
  language: &#34;en&#34;,
  notificationsEnabled: true
});</code></pre></div>
</div>
<table>
  <thead>
      <tr>
          <th>RudderStack property</th>
          <th>Pushwoosh property</th>
          <th>Notes</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>userId</code> <br/> Required</td>
          <td><code>request.userId</code></td>
          <td>Sent as a string.</td>
      </tr>
      <tr>
          <td><code>traits</code> <br/> <code>context.traits</code> <br/> Required</td>
          <td><code>request.tags</code></td>
          <td><code>traits</code> takes precedence. Excluded keys are removed, then values are sanitized. At least one trait must remain.</td>
      </tr>
  </tbody>
</table>

<blockquote class="warning">
  <div class="tip-quote">
    
    <div class="tip-text"><p>Identity and PII traits are never sent as tags. These keys are excluded:</p>
<ul>
<li><code>userId</code></li>
<li><code>id</code></li>
<li><code>anonymousId</code></li>
<li><code>email</code></li>
<li><code>phone</code></li>
<li><code>firstName</code></li>
<li><code>lastName</code></li>
<li><code>name</code></li>
<li><code>address</code></li>
</ul></div>
  </div>
</blockquote>
<!-- end-chunk -->
<!-- begin-chunk -->
<h4 id="value-handling">Value handling</h4><p>The same sanitization applies to identify tags and track attributes:</p>
<ul>
<li>Drop <code>null</code> and <code>undefined</code> values.</li>
<li>Leave strings, numbers, and booleans unchanged.</li>
<li>Send nested objects as JSON strings.</li>
<li>Keep arrays and JSON-stringify any object elements within arrays.</li>
</ul>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="track">Track</h2><p>A <code>track</code> call sends a Pushwoosh custom event. See the <a href="https://www.rudderstack.com/docs/event-spec/standard-events/track/" >Track</a> event for the call format.</p>
<p>A sample <code>track</code> call:</p>
<div class="rs-code">
  <div class="rs-code__head">javascript<button class="rs-code__copy" type="button">
      
      Copy
    </button>
  </div>
  <div class="highlight"><pre class="chroma"><code class="language-javascript" data-lang="javascript">rudderanalytics.track(&#34;Product Viewed&#34;, {
  productId: &#34;sku-100&#34;,
  price: 25,
  inStock: true
});</code></pre></div>
</div>
<table>
  <thead>
      <tr>
          <th>RudderStack property</th>
          <th>Pushwoosh property</th>
          <th>Notes</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>userId</code> <br/> Required</td>
          <td><code>user_id</code></td>
          <td>Sent as a string.</td>
      </tr>
      <tr>
          <td><code>event</code> <br/> Required</td>
          <td><code>name</code></td>
          <td>Sent as a string.</td>
      </tr>
      <tr>
          <td><code>properties</code></td>
          <td><code>attributes</code></td>
          <td>Sanitized. Defaults to <code>{}</code> when absent. See <a href="https://www.rudderstack.com/docs/destinations/streaming-destinations/pushwoosh/cloud-mode/#value-handling" >Value handling</a>.</td>
      </tr>
      <tr>
          <td><code>context.device.id</code></td>
          <td><code>device_id</code></td>
          <td>Empty string when absent. Pushwoosh still stores the event against <code>user_id</code>.</td>
      </tr>
      <tr>
          <td><code>context.device.type</code> <br/> <code>context.os.name</code></td>
          <td><code>device_platform</code></td>
          <td>Resolves to <code>android</code>, <code>ios</code>, or <code>web</code>.</td>
      </tr>
      <tr>
          <td><code>timestamp</code> <br/> <code>originalTimestamp</code></td>
          <td><code>timestamp</code></td>
          <td>First present wins, converted to ISO 8601 UTC. Omitted when neither is present.</td>
      </tr>
  </tbody>
</table>
<p><code>track</code> events are grouped into requests of up to 100.</p>
<!-- end-chunk -->
<!-- begin-chunk -->
<h4 id="device-platform">Device platform</h4><p><code>device_platform</code> resolves from <code>context.device.type</code> and <code>context.os.name</code>:</p>
<ul>
<li>It resolves to <code>android</code> when <code>context.device.type</code> or <code>context.os.name</code> is <code>android</code>.</li>
<li>It resolves to <code>ios</code> for <code>ios</code>, <code>ipados</code>, <code>watchos</code>, or <code>tvos</code>.</li>
<li>It resolves to <code>web</code> otherwise.</li>
</ul>
<p>Pushwoosh accepts only these three values.</p>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="unsupported-events">Unsupported events</h2><p>Cloud mode rejects <code>page</code>, <code>screen</code>, <code>group</code>, <code>alias</code>, and <code>record</code> events with a 400 response.</p>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="error-handling">Error handling</h2><table>
  <thead>
      <tr>
          <th>Error type</th>
          <th>HTTP code</th>
          <th>Description</th>
          <th>Retry strategy</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Missing <code>userId</code></td>
          <td>400</td>
          <td><code>userId</code> is absent from the event</td>
          <td>Not retried</td>
      </tr>
      <tr>
          <td>Missing <code>event</code></td>
          <td>400</td>
          <td>A <code>track</code> event has no event name</td>
          <td>Not retried</td>
      </tr>
      <tr>
          <td>No traits to send</td>
          <td>400</td>
          <td>Every trait was excluded as identity or PII, or none were supplied</td>
          <td>Not retried</td>
      </tr>
      <tr>
          <td>Unsupported event type</td>
          <td>400</td>
          <td>Event type other than <code>track</code> or <code>identify</code></td>
          <td>Not retried</td>
      </tr>
      <tr>
          <td>Invalid timestamp</td>
          <td>400</td>
          <td><code>timestamp</code> or <code>originalTimestamp</code> can&rsquo;t be parsed as a date</td>
          <td>Not retried</td>
      </tr>
      <tr>
          <td>Missing credentials</td>
          <td>400</td>
          <td>Application Code or API Token not supplied</td>
          <td>Not retried</td>
      </tr>
      <tr>
          <td>Application not found</td>
          <td>400</td>
          <td>Application Code is wrong, or the account isn&rsquo;t in the EU (NUE) data center</td>
          <td>Not retried</td>
      </tr>
      <tr>
          <td>Unauthorized</td>
          <td>401</td>
          <td>API Token doesn&rsquo;t match the Application Code</td>
          <td>Not retried</td>
      </tr>
      <tr>
          <td>Invalid application code</td>
          <td>200 with <code>status_code</code> 210</td>
          <td>Returned by the tags API; usually an Application Code or region mismatch</td>
          <td>Not retried</td>
      </tr>
      <tr>
          <td>Rate limit exceeded</td>
          <td>429</td>
          <td>Too many requests</td>
          <td>Retried with exponential backoff</td>
      </tr>
      <tr>
          <td>Server error</td>
          <td>5xx</td>
          <td>Pushwoosh server error</td>
          <td>Retried with exponential backoff</td>
      </tr>
  </tbody>
</table>
<p>If one event in a batch is malformed, RudderStack resends that batch one event at a time. Only the offending event fails, and the rest are delivered.</p>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="faq">FAQ</h2><!-- end-chunk -->
<!-- begin-chunk -->
<h4 id="why-do-identify-events-succeed-but-no-tags-appear-in-pushwoosh">Why do identify events succeed but no tags appear in Pushwoosh?</h4><p>Tags only land on a user who already has a device registered through the Pushwoosh SDK with the same User ID. Pushwoosh also writes only user-specific tags. A new tag name is automatically created as user-specific, but a pre-existing tag with the same name that isn&rsquo;t user-specific is silently skipped. Neither case returns an error.</p>
<!-- end-chunk -->
<!-- begin-chunk -->
<h4 id="does-a-wrong-api-token-fail-identify-events">Does a wrong API Token fail identify events?</h4><p>No. The tags API doesn&rsquo;t validate the token, so <code>identify</code> events are still delivered. <code>track</code> events fail with <code>401 unauthorized</code>, which is the signal to check the token.</p>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="see-more">See more</h2><ul>
<li><a href="https://www.rudderstack.com/docs/destinations/streaming-destinations/pushwoosh/setup-guide/" >Pushwoosh Setup Guide</a></li>
</ul>

