> ## Documentation Index
> Fetch the complete documentation index at: https://developers.redo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# CampaignAnalytics

> Analytics for this campaign. Each field beneath is a separate read against a different store, with its own arguments and its own scope.

<ResponseField name="messaging" type={<a href="/docs/api-reference/v3/reference/marketing/campaign-messaging-analytics">CampaignMessagingAnalytics!</a>} required>
  Email and SMS performance, read from the analytics warehouse: what was sent, how it was engaged with, and the orders and revenue attributed to it.

  **Requires:** [`campaigns_analytics_read`](/docs/api-reference/v3/reference/scopes#scope-campaigns_analytics_read)

  <Expandable title="fields" lazyRender>
    **Arguments**

    <ResponseField name="attributionWindowDays" type="Int">
      How many days after a message an order still counts toward it, 1-30.
    </ResponseField>

    <ResponseField name="endDate" type={<a href="/docs/api-reference/v3/reference/common/date">Date!</a>} required>
      Last day to report on, inclusive, in the store's timezone. The range may span at most 400 days.
    </ResponseField>

    <ResponseField name="startDate" type={<a href="/docs/api-reference/v3/reference/common/date">Date!</a>} required>
      First day to report on, inclusive, in the store's timezone. Must be on or before `endDate`, and the range may span at most 400 days.
    </ResponseField>

    **Fields**

    <ResponseField name="series" type={<a href="/docs/api-reference/v3/reference/marketing/message-analytics-point">[MessageAnalyticsPoint!]!</a>} required>
      One entry per day with activity, oldest first. Quiet days are omitted rather than reported as zero.

      <Expandable title="fields" lazyRender>
        <ResponseField name="averageOrderValue" type={<a href="/docs/api-reference/v3/reference/common/money">Money</a>}>
          `revenue / orders`. Null when there were no orders.
        </ResponseField>

        <ResponseField name="byChannel" type={<a href="/docs/api-reference/v3/reference/marketing/message-channel-analytics">[MessageChannelAnalytics!]!</a>} required>
          The same analytics split by channel. A campaign sends on one channel; an automation whose steps include both an email and an SMS reports both.
        </ResponseField>

        <ResponseField name="clickThroughRate" type="Float">
          `uniqueClicks / delivered`. Null when nothing was delivered.
        </ResponseField>

        <ResponseField name="clickToOpenRate" type="Float">
          `uniqueClicks / uniqueOpens`. Null when nothing was opened, so null on SMS.
        </ResponseField>

        <ResponseField name="conversionRate" type="Float">
          `orders / delivered`. Null when nothing was delivered.
        </ResponseField>

        <ResponseField name="date" type={<a href="/docs/api-reference/v3/reference/common/date">Date!</a>} required>
          The day these analytics cover, in the store's timezone. Engagement counts are keyed to the day the message went out; orders and revenue to the day the order was placed. A rate combining the two — conversion rate, revenue per recipient, average order value — therefore relates figures from different days, and is most meaningful read over the whole range rather than per day.
        </ResponseField>

        <ResponseField name="delivered" type="Int!" required>
          Messages the provider confirmed were delivered.
        </ResponseField>

        <ResponseField name="deliveryRate" type="Float">
          `delivered / sends`. Null when nothing was sent.
        </ResponseField>

        <ResponseField name="failures" type="Int!" required>
          Messages the delivery provider refused or gave up on, so they never reached a delivery attempt. Distinct from a bounce, which is a delivery that came back — these never left. Together with `delivered` they account for what `sends` became.
        </ResponseField>

        <ResponseField name="newCustomerOrders" type="Int!" required>
          Attributed orders that are this customer's first paid order Redo has for the store. Complements `returningCustomerOrders`; the two sum to `orders`. Customers whose earlier orders fall outside the history Redo has synced are counted as new.
        </ResponseField>

        <ResponseField name="newCustomerRevenue" type={<a href="/docs/api-reference/v3/reference/common/money">Money!</a>} required>
          Attributed revenue from `newCustomerOrders`. Complements `returningCustomerRevenue`. Warehouse amounts sum to `revenue` before each is rounded to currency precision.
        </ResponseField>

        <ResponseField name="openRate" type="Float">
          `uniqueOpens / delivered`, over email deliveries only. Null when nothing measurable was delivered — including an SMS-only send, where opens do not exist and a rate of 0 would be misleading. For a continuously-sending automation this can exceed 1, since opens inside the range may belong to sends made before it.
        </ResponseField>

        <ResponseField name="orders" type="Int!" required>
          Orders attributed to this send within the attribution window.
        </ResponseField>

        <ResponseField name="recipients" type="Int!" required>
          Distinct customers sent to, counted once per day.
        </ResponseField>

        <ResponseField name="returningCustomerOrders" type="Int!" required>
          Attributed orders from customers who already had an earlier paid order on this store. Complements `newCustomerOrders`; the two sum to `orders`.
        </ResponseField>

        <ResponseField name="returningCustomerRevenue" type={<a href="/docs/api-reference/v3/reference/common/money">Money!</a>} required>
          Attributed revenue from `returningCustomerOrders`. Complements `newCustomerRevenue`. Warehouse amounts sum to `revenue` before each is rounded to currency precision.
        </ResponseField>

        <ResponseField name="revenue" type={<a href="/docs/api-reference/v3/reference/common/money">Money!</a>} required>
          Revenue attributed to this send.
        </ResponseField>

        <ResponseField name="revenuePerRecipient" type={<a href="/docs/api-reference/v3/reference/common/money">Money</a>}>
          `revenue / recipients`. Carries extra decimal places, since per-recipient revenue is routinely sub-cent. Null when nothing was sent.
        </ResponseField>

        <ResponseField name="revenuePerSend" type={<a href="/docs/api-reference/v3/reference/common/money">Money</a>}>
          `revenue / sends` — what a message returned, where `revenuePerRecipient` is what a customer returned. The two agree for a campaign, which sends to each recipient once, and diverge for a continuously-running automation that messages the same customer repeatedly over the range. This is the figure to compare against `spend`, which is also per message. Carries extra decimal places, since per-send revenue is routinely sub-cent. Null when nothing was sent.
        </ResponseField>

        <ResponseField name="sends" type="Int!" required>
          Messages handed to the delivery provider.
        </ResponseField>

        <ResponseField name="spend" type={<a href="/docs/api-reference/v3/reference/common/money">Money!</a>} required>
          What the store was billed to send these messages: its per-message rate plus any carrier fees. **Always USD**, unlike `revenue`, which is in the store's own currency — Redo prices messaging in dollars. Convert before combining the two. Carries extra decimal places, since one message costs a fraction of a cent.
        </ResponseField>

        <ResponseField name="uniqueClicks" type="Int!" required>
          Customers who clicked, counted once per day.
        </ResponseField>

        <ResponseField name="uniqueOpens" type="Int!" required>
          Customers who opened, counted once per day — so a customer who opens on two days counts twice over a range. Always 0 on SMS, which has no open tracking.
        </ResponseField>

        <ResponseField name="unsubscribeRate" type="Float">
          `unsubscribes / delivered`. Rated against deliveries rather than sends, like the other engagement rates, so it answers what share of messages that arrived cost a subscriber. Null when nothing was delivered.
        </ResponseField>

        <ResponseField name="unsubscribes" type="Int!" required>
          Customers who opted out of marketing off the back of this send. Only opt-outs the warehouse could attribute to a specific campaign or automation are counted, so these do **not** sum to the store's total unsubscribes over the same period — an opt-out arriving without that attribution belongs to no send and is absent here.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="totals" type={<a href="/docs/api-reference/v3/reference/marketing/message-analytics-totals">MessageAnalyticsTotals!</a>} required>
      Totals across the whole range. A campaign with no activity reports zero counts and null rates.

      <Expandable title="fields" lazyRender>
        <ResponseField name="averageOrderValue" type={<a href="/docs/api-reference/v3/reference/common/money">Money</a>}>
          `revenue / orders`. Null when there were no orders.
        </ResponseField>

        <ResponseField name="byChannel" type={<a href="/docs/api-reference/v3/reference/marketing/message-channel-analytics">[MessageChannelAnalytics!]!</a>} required>
          The same analytics split by channel. A campaign sends on one channel; an automation whose steps include both an email and an SMS reports both.
        </ResponseField>

        <ResponseField name="clickThroughRate" type="Float">
          `uniqueClicks / delivered`. Null when nothing was delivered.
        </ResponseField>

        <ResponseField name="clickToOpenRate" type="Float">
          `uniqueClicks / uniqueOpens`. Null when nothing was opened, so null on SMS.
        </ResponseField>

        <ResponseField name="conversionRate" type="Float">
          `orders / delivered`. Null when nothing was delivered.
        </ResponseField>

        <ResponseField name="delivered" type="Int!" required>
          Messages the provider confirmed were delivered.
        </ResponseField>

        <ResponseField name="deliveryRate" type="Float">
          `delivered / sends`. Null when nothing was sent.
        </ResponseField>

        <ResponseField name="failures" type="Int!" required>
          Messages the delivery provider refused or gave up on, so they never reached a delivery attempt. Distinct from a bounce, which is a delivery that came back — these never left. Together with `delivered` they account for what `sends` became.
        </ResponseField>

        <ResponseField name="newCustomerOrders" type="Int!" required>
          Attributed orders that are this customer's first paid order Redo has for the store. Complements `returningCustomerOrders`; the two sum to `orders`. Customers whose earlier orders fall outside the history Redo has synced are counted as new.
        </ResponseField>

        <ResponseField name="newCustomerRevenue" type={<a href="/docs/api-reference/v3/reference/common/money">Money!</a>} required>
          Attributed revenue from `newCustomerOrders`. Complements `returningCustomerRevenue`. Warehouse amounts sum to `revenue` before each is rounded to currency precision.
        </ResponseField>

        <ResponseField name="openRate" type="Float">
          `uniqueOpens / delivered`, over email deliveries only. Null when nothing measurable was delivered — including an SMS-only send, where opens do not exist and a rate of 0 would be misleading. For a continuously-sending automation this can exceed 1, since opens inside the range may belong to sends made before it.
        </ResponseField>

        <ResponseField name="orders" type="Int!" required>
          Orders attributed to this send within the attribution window.
        </ResponseField>

        <ResponseField name="recipients" type="Int!" required>
          Distinct customers sent to, counted once per day.
        </ResponseField>

        <ResponseField name="returningCustomerOrders" type="Int!" required>
          Attributed orders from customers who already had an earlier paid order on this store. Complements `newCustomerOrders`; the two sum to `orders`.
        </ResponseField>

        <ResponseField name="returningCustomerRevenue" type={<a href="/docs/api-reference/v3/reference/common/money">Money!</a>} required>
          Attributed revenue from `returningCustomerOrders`. Complements `newCustomerRevenue`. Warehouse amounts sum to `revenue` before each is rounded to currency precision.
        </ResponseField>

        <ResponseField name="revenue" type={<a href="/docs/api-reference/v3/reference/common/money">Money!</a>} required>
          Revenue attributed to this send.
        </ResponseField>

        <ResponseField name="revenuePerRecipient" type={<a href="/docs/api-reference/v3/reference/common/money">Money</a>}>
          `revenue / recipients`. Carries extra decimal places, since per-recipient revenue is routinely sub-cent. Null when nothing was sent.
        </ResponseField>

        <ResponseField name="revenuePerSend" type={<a href="/docs/api-reference/v3/reference/common/money">Money</a>}>
          `revenue / sends` — what a message returned, where `revenuePerRecipient` is what a customer returned. The two agree for a campaign, which sends to each recipient once, and diverge for a continuously-running automation that messages the same customer repeatedly over the range. This is the figure to compare against `spend`, which is also per message. Carries extra decimal places, since per-send revenue is routinely sub-cent. Null when nothing was sent.
        </ResponseField>

        <ResponseField name="sends" type="Int!" required>
          Messages handed to the delivery provider.
        </ResponseField>

        <ResponseField name="spend" type={<a href="/docs/api-reference/v3/reference/common/money">Money!</a>} required>
          What the store was billed to send these messages: its per-message rate plus any carrier fees. **Always USD**, unlike `revenue`, which is in the store's own currency — Redo prices messaging in dollars. Convert before combining the two. Carries extra decimal places, since one message costs a fraction of a cent.
        </ResponseField>

        <ResponseField name="uniqueClicks" type="Int!" required>
          Customers who clicked, counted once per day.
        </ResponseField>

        <ResponseField name="uniqueOpens" type="Int!" required>
          Customers who opened, counted once per day — so a customer who opens on two days counts twice over a range. Always 0 on SMS, which has no open tracking.
        </ResponseField>

        <ResponseField name="unsubscribeRate" type="Float">
          `unsubscribes / delivered`. Rated against deliveries rather than sends, like the other engagement rates, so it answers what share of messages that arrived cost a subscriber. Null when nothing was delivered.
        </ResponseField>

        <ResponseField name="unsubscribes" type="Int!" required>
          Customers who opted out of marketing off the back of this send. Only opt-outs the warehouse could attribute to a specific campaign or automation are counted, so these do **not** sum to the store's total unsubscribes over the same period — an opt-out arriving without that attribution belongs to no send and is absent here.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.