How to Send Klaviyo Campaign Metrics to Power BI
Pull Klaviyo campaign performance (opens, clicks, conversions and revenue) through the Klaviyo Reporting API every morning and push it into Power BI, so email results sit next to sales and ad spend in one report.
What This Integration Does
Klaviyo's own dashboards are good for email, but they do not join with your order data, ad spend or finance numbers. Power BI can, once the numbers are there. This Spojit workflow calls Klaviyo's campaign values report each morning, which returns the same statistics Klaviyo shows in its campaign reports (recipients, opens, clicks, conversions, conversion value, unsubscribes), one row per campaign. It then pushes the rows, stamped with the report date, into a Power BI push dataset. Over time the dataset becomes a daily history of every campaign's performance that you can chart and compare.
Each run requests a fixed timeframe (the last 30 days by default) and stamps every row with the run date, so a campaign appears once per day with its running totals. That makes trends easy to chart and means a re-run on the same day only adds a duplicate snapshot, which a Power BI measure can ignore by taking the latest snapshot per campaign.
Prerequisites
- A Klaviyo connection in Spojit with a private API key that has read access to Campaigns, Metrics and Reports. The connection's API revision must be one that includes the Reporting API (2024-06-15 or later).
- The ID of your conversion metric, usually Placed Order. Find it once with the Klaviyo connector's
raw-api-requesttool,GET/metrics, and copy the ID of the metric named Placed Order. - A Power BI HTTP Requests connection (OAuth 2.0) and push dataset, as in the "How to Push JSON Data into Power BI from Any Workflow" tutorial in this help center, with a
CampaignStatstable:snapshot_date(DateTime),campaign_id(String),channel(String),recipients(Int64),opens_unique(Int64),clicks_unique(Int64),conversions(Int64),conversion_value(Double),unsubscribes(Int64),open_rate(Double),click_rate(Double).
Step 1: Schedule Trigger
Add a Trigger node with type Schedule and cron 0 7 * * * in your marketing team's timezone, so the report is ready before the morning meeting.
Step 2: Request the Campaign Values Report
Add a Connector node on Klaviyo in Direct Mode with raw-api-request:
method:POSTpath:/campaign-values-reportsbody:{ "data": { "type": "campaign-values-report", "attributes": { "statistics": [ "recipients", "opens_unique", "clicks_unique", "conversions", "conversion_value", "unsubscribes", "open_rate", "click_rate" ], "timeframe": { "key": "last_30_days" }, "conversion_metric_id": "YOUR_PLACED_ORDER_METRIC_ID" } } }
Name the output report. The response contains a list of results, each with groupings (the campaign_id and send_channel) and statistics (the numbers you asked for). Run the step once and copy the path to that list from the output panel.
Step 3: Get Campaign Names (Optional)
The report identifies campaigns by ID. To show names in Power BI, add a Klaviyo step with list-campaigns and push the ID, name and send time into a small Campaigns table once a day, then relate it to CampaignStats on campaign_id. Klaviyo requires a channel filter when listing campaigns, so filter on email (and run it again for SMS if you use it).
Step 4: Shape the Rows
Add a Transform node with Iterate over set to the report results:
{
"snapshot_date": "(the trigger date, ISO 8601)",
"campaign_id": "{{ item.groupings.campaign_id }}",
"channel": "{{ item.groupings.send_channel }}",
"recipients": {{ item.statistics.recipients }},
"opens_unique": {{ item.statistics.opens_unique }},
"clicks_unique": {{ item.statistics.clicks_unique }},
"conversions": {{ item.statistics.conversions }},
"conversion_value": {{ item.statistics.conversion_value }},
"unsubscribes": {{ item.statistics.unsubscribes }},
"open_rate": {{ item.statistics.open_rate }},
"click_rate": {{ item.statistics.click_rate }}
}
Name the output rows.
Step 5: Push to Power BI
Add a Connector node on the Power BI HTTP connection with http-post, url /groups/YOUR_WORKSPACE_ID/datasets/YOUR_DATASET_ID/tables/CampaignStats/rows and body { "rows": {{ rows }} }.
In Power BI, create a measure that keeps only the latest snapshot per campaign (filter snapshot_date to its maximum) for "current totals" visuals, and use all snapshots for trend lines.
Tips
- Flows too: the same pattern works for flows with
/flow-values-reportsand"type": "flow-values-report". Push them into a separateFlowStatstable. - Revenue attribution:
conversion_valueuses Klaviyo's attribution window. Compare it with order revenue from your store in the same report, but do not add the two together. - Custom ranges: replace the
keywith{ "start": "...", "end": "..." }for a fixed period. Klaviyo allows a window of up to one year. - Agent Mode summary: add an Agent Mode step after the report to write a three-line "what changed this week" summary and post it to Slack alongside the dashboard link.
Common Pitfalls
- Tight rate limits: Klaviyo limits the reporting endpoints far more strictly than the rest of its API (only a few requests per minute and a daily cap). One report request per day per report type is fine; do not call it inside a loop.
- Old API revision: if the connection's revision predates the Reporting API, the request fails with a not-found error. Update the revision on the connection.
- Wrong conversion metric: conversion statistics depend on
conversion_metric_id. Using a metric other than Placed Order gives numbers that do not match Klaviyo's UI. - Push dataset retirement: Microsoft plans to stop creation of new push datasets on 31 October 2027; for long-term history, land the snapshots in a database Power BI reads.
Testing
Run the workflow manually and compare two or three campaigns' open and click rates with the same campaigns in Klaviyo's campaign report for the last 30 days. When they match, turn on the daily schedule.