HomeGuidesAPI Reference
ChangelogHelp CenterCommunityContact Us
Guides

Integrate an analytics and reporting platform

Learn how to integrate an analytics, attribution, or BI platform with Klaviyo.

Overview

This resource will help you as you build an integration between an analytics, attribution, or business intelligence (BI) platform and Klaviyo. Unlike most integrations in this section, this one is primarily a read integration: you pull Klaviyo's performance, event, and profile data out to build dashboards, attribution models, and warehouses. This guide walks through what to pull and from where, the Reporting API, pull patterns, an optional write-back, and the authentication requirements, with an API quick reference at the end.

Why connect your analytics platform to Klaviyo

Email and SMS are among the highest-ROI channels a brand runs, and for most merchants Klaviyo is where that revenue is generated and measured. An analytics or attribution platform that can't see Klaviyo's numbers is blind to a huge share of owned-channel revenue. Pulling Klaviyo data in gives merchants the complete picture:

  • Blended ROAS, not paid-only. Combining Klaviyo campaign and flow revenue with ad spend gives true return on marketing, not just paid-media return.
  • LTV and CAC by acquisition source. Joining Klaviyo profile and order data against first-touch channel answers which sources produce the most valuable customers.
  • Owned-channel performance in the warehouse. Landing campaign, flow, and form reporting in a data warehouse lets merchants build custom BI alongside every other source.
  • Cross-channel attribution. Klaviyo engagement as an input to a multi-touch model closes the gap between "sent an email" and "drove a sale."
  • Stickier merchants. When a merchant's core dashboards depend on Klaviyo data, the integration rarely gets turned off.

Short version: pulling Klaviyo's campaign, flow, and metric performance into your platform lets the merchant measure owned-channel revenue alongside everything else they track.

The flow

Primarily pull, your platform reading from Klaviyo. Klaviyo is the source of truth for engagement and profile data; your platform is the consumer. There are two things to get right:

  • Reporting reads for aggregated performance. Campaign, flow, form, and segment reports, plus raw metric aggregation. This is the heart of the integration.
  • Object reads for the underlying records. Events, profiles, lists, segments, and the metadata that ties reports back to named campaigns and flows.

Identity matching is your problem, not Klaviyo's. Klaviyo returns profiles keyed by email, phone, or external ID; you join that to your own customer and order graph, usually on email or a shared external ID. There's no PII-hashing handoff as there is for an ad platform; you just need a stable join key.

An optional write-back exists and is common: after your model runs, write computed attributes (LTV, predicted value, attribution source) back onto the Klaviyo profile so the merchant can segment on them. See Optional write-back below. "Mostly read" does not mean "read only."

What to pull

Data you wantEndpointScope
Campaign performancePOST /api/campaign-values-reports/campaigns:read
Flow performance (totals)POST /api/flow-values-reports/flows:read
Flow performance (time series)POST /api/flow-series-reports/flows:read
Form performancePOST /api/form-values-reports/, POST /api/form-series-reports/forms:read
Segment size and growthPOST /api/segment-values-reports/, POST /api/segment-series-reports/segments:read
Raw event aggregationPOST /api/metric-aggregates/metrics:read
Metric catalog (get metric IDs)GET /api/metrics/metrics:read
Raw events (timeline)GET /api/events/events:read
ProfilesGET /api/profiles/profiles:read
ListsGET /api/lists/lists:read
Segment metadataGET /api/segments/segments:read
Campaign / flow metadataGET /api/campaigns/, GET /api/flows/campaigns:read / flows:read

There is no separate reports:read scope. Each Reporting API endpoint reuses the scope of its underlying resource: a campaign report needs campaigns:read, a flow report needs flows:read, and so on.

The Reporting API

The Reporting API is the heart of this integration. It returns the same numbers the merchant sees in the Klaviyo UI, which is exactly what you want for anything they'll compare against Klaviyo directly.

Reports come in two shapes:

  • Values reports return totals over a timeframe.
  • Series reports return the same statistics broken into buckets by an interval (daily, weekly, monthly, and so on), with a date_times array to align against.

Every reporting endpoint is a POST. The request body (under data.attributes) takes:

  • statistics (required): the metrics to return, for example opens_unique, click_rate, conversion_value, revenue_per_recipient.
  • timeframe (required): either a key like { "key": "last_30_days" } or a custom { "start", "end" } range, up to a one-year span.
  • conversion_metric_id (required): the metric ID that defines a conversion, typically Placed Order. Get it from GET /api/metrics/.
  • filter (optional): a JSON:API filter string, one condition per attribute, combined with AND only.
  • group_by (optional): dimensions such as campaign_id and send_channel.
  • interval (series reports only).

The response is a results array of { groupings, statistics }, with relationships back to the named campaigns, flows, and messages so you can resolve IDs to human-readable names.

Reporting API versus Query Metric Aggregates

There are two ways to get aggregated numbers, and they don't reconcile, which is the single most common source of confusion:

  • The Reporting API groups by send date, matching the Klaviyo UI. Use it for anything a merchant will compare against Klaviyo's own dashboards.
  • Query Metric Aggregates (POST /api/metric-aggregates/) groups by event-occurrence time, and lets you roll up arbitrary event data by custom dimensions ($attributed_flow, $message, custom properties). Use it for flexible, SQL-style rollups that don't need to match the UI.

Pick deliberately and tell the merchant which one a given number came from. A "why don't these match" support ticket almost always traces back to mixing the two.

Pull patterns

  • Cursor pagination. Object reads (GET /api/events/, GET /api/profiles/) use JSON:API cursor pagination. Follow links.next until it's null. Don't compute offsets.
  • Incremental sync. Store a high-water mark and use the filter DSL to pull only what changed: filter=greater-than(datetime,2026-06-01T00:00:00Z) on events, filter=greater-than(updated,2026-06-01T00:00:00Z) on profiles.
  • Large historical pulls. There is no bulk-export job endpoint (unlike bulk import). For large backfills, page through the object endpoints, or use Klaviyo's scheduled data export options and prebuilt ETL connectors (Fivetran, Stitch, Segment, and the open-source tap-klaviyo Singer tap) rather than hammering the API.
  • Cadence. Reporting endpoints are tightly rate-limited (see below), so pull them a few times a day at most and cache aggressively. Incremental object reads can run hourly. Backfill once, then sync deltas.

Optional write-back

After your model runs, you can write results back onto the Klaviyo profile so the merchant can segment and automate on them:

  • Computed properties. Write LTV, predicted value, or attribution source as a custom property via Update Profile (PATCH /api/profiles/{id}/) for single writes, or Bulk Import Profiles (POST /api/profile-bulk-import-jobs/) for large batches. Requires profiles:write.
  • Enrichment events. Push events sourced from your own pixel or model back via POST /api/events/ to increase flow-trigger volume. Requires events:write.

Keep write-back explicitly secondary. The primary flow is read, and you should only request write scopes if you actually use them.

Auth and scopes

Build as a public OAuth app. Private API keys are a non-starter for the marketplace. Start with the Create a public OAuth app guide.

Key OAuth specifics for analytics integrations:

  • PKCE is required on the authorization code exchange (code_verifier must be included).
  • Access tokens are short-lived (1 hour). Refresh tokens are long-lived but rotate on every use. Persist the latest refresh token after every refresh call, or you'll lose the integration on the next refresh.
  • Tokens are scoped per Klaviyo account. Agencies and platforms serving many merchants connect each account separately.

Scopes to request (read):

  • campaigns:read, flows:read, forms:read, segments:read for the reporting endpoints.
  • metrics:read for the metric catalog and metric aggregates.
  • events:read, profiles:read, lists:read for raw object reads.
  • tags:read only if you group or filter reports by tag.

Add write scopes only for the optional write-back:

  • profiles:write to write computed properties back.
  • events:write to push enrichment events back.

Don't over-scope. Requesting write scopes on a read-only integration gets flagged in marketplace review. Once functional, submit for App Marketplace review under the analytics and reporting category. Plan for at least one round of feedback covering OAuth, scopes, install and uninstall validation, and that the integration delivers what your listing claims.

API quick reference

Concrete specs for AI coding assistants and engineers grounding on this doc. The narrative above is the why and the flow. This section is the what-to-actually-type.

Headers (required on every request)

Authorization: Bearer <oauth_access_token>
revision: 2026-04-15
Accept: application/json
Content-Type: application/json

Pin the revision header to a specific date when you ship. Check the API versioning guide for the current latest. Without it you'll get a 400.

Campaign values report

Pull campaign performance for a timeframe, grouped by campaign. Get conversion_metric_id from GET /api/metrics/ (the Placed Order metric).

POST /api/campaign-values-reports/

{
  "data": {
    "type": "campaign-values-report",
    "attributes": {
      "statistics": ["opens_unique", "click_rate", "conversion_value", "revenue_per_recipient"],
      "timeframe": { "key": "last_30_days" },
      "conversion_metric_id": "RESQ6t",
      "group_by": ["campaign_id", "send_channel"]
    }
  }
}

Query metric aggregates

Roll up a metric by event-occurrence time and custom dimensions. The filter must bound the time range.

POST /api/metric-aggregates/

{
  "data": {
    "type": "metric-aggregate",
    "attributes": {
      "metric_id": "RESQ6t",
      "measurements": ["sum_value", "count"],
      "interval": "day",
      "by": ["$attributed_flow"],
      "filter": [
        "greater-or-equal(datetime,2026-05-01T00:00:00Z)",
        "less-than(datetime,2026-06-01T00:00:00Z)"
      ],
      "timezone": "America/New_York"
    }
  }
}

Incremental object read

Page through events changed since your high-water mark; follow the cursor.

GET /api/events/?filter=greater-than(datetime,2026-06-01T00:00:00Z)&page[size]=200
→ response.links.next contains the full next-page URL
→ loop until links.next is null

Retries

  • 429: respect the Retry-After header. Otherwise exponential backoff starting at 1s, cap at 60s, max 5 retries.
  • 503: respect Retry-After.
  • 5xx: same backoff.
  • 4xx (other than 429): don't retry. Log and surface to the merchant.

Rate limits

Per-account, not per-app. Reporting endpoints are tightly rate-limited relative to object reads, with low steady rates and a modest daily cap, so cache aggressively and pull them only a few times a day. Raw GET /api/events/ and GET /api/profiles/ have much higher limits but are still per-account, so a platform serving many merchants can be throttled account by account. Verify current limits in the developer docs at ship time. For merchants at unusual scale, request per-account increases through Klaviyo Support and CSM before launch.

Glossary

  • Klaviyo profile: customer record. Keyed by email, phone, or external ID. Your join key back to your own customer graph.
  • Klaviyo metric: event type. "Placed Order," "Opened Email," etc. Its ID is the conversion_metric_id in reports.
  • Values report: a report returning totals over a timeframe.
  • Series report: a report returning statistics bucketed by an interval, with a date_times array.
  • Conversion metric: the metric that defines a conversion for a report, typically Placed Order.
  • Query Metric Aggregates: the endpoint for flexible event rollups grouped by event-occurrence time, distinct from the Reporting API's send-date grouping.
  • High-water mark: the last-synced timestamp you store to pull only what changed on the next run.

Resources


Did this page help you?