---
name: pp-klaviyo
description: "Klaviyo from the shell, with local customer-behavior analytics layered on top. Trigger phrases: `inspect a Klaviyo profile`, `deploy a Klaviyo campaign`, `check Klaviyo flow decay`, `reconcile Klaviyo campaign revenue`."
author: "Cathryn Lavery"
license: "Apache-2.0"
argument-hint: "<command> [args] | install cli|mcp"
allowed-tools: "Read Bash"
metadata:
  openclaw:
    requires:
      bins:
        - klaviyo-pp-cli
    install:
      - kind: go
        bins: [klaviyo-pp-cli]
        module: github.com/mvanhorn/printing-press-library/library/marketing/klaviyo/cmd/klaviyo-pp-cli
---
<!-- GENERATED FILE — DO NOT EDIT.
     This file is a verbatim mirror of library/marketing/klaviyo/SKILL.md,
     regenerated post-merge by tools/generate-skills/. Hand-edits here are
     silently overwritten on the next regen. Edit the library/ source instead.
     See the repository agent guide, section "Generated artifacts: registry.json, cli-skills/". -->

# Klaviyo - Printing Press CLI

## Prerequisites: Install the CLI

This skill drives the `klaviyo-pp-cli` binary. **You must verify the CLI is installed before invoking any command from this skill.** If it is missing, install it first:

1. Install via the Printing Press installer. It defaults binaries to `$HOME/.local/bin` on macOS/Linux and `%LOCALAPPDATA%\Programs\PrintingPress\bin` on Windows:
   ```bash
   npx -y @mvanhorn/printing-press-library install klaviyo --cli-only
   ```
2. Verify: `klaviyo-pp-cli --version`
3. Ensure the reported install directory is on `$PATH` for the agent/runtime that will invoke this skill.

If the `npx` install fails (no Node, offline, etc.), fall back to a direct Go install (requires Go 1.26.6 or newer):

```bash
go install github.com/mvanhorn/printing-press-library/library/marketing/klaviyo/cmd/klaviyo-pp-cli@latest
```

If `--version` reports "command not found" after install, the runtime cannot see the binary directory on `$PATH`. Do not proceed with skill commands until verification succeeds.

## When to Use This CLI

Use this CLI when an agent needs to inspect or operate Klaviyo without the web UI, especially for profiles, events, campaigns, flows, segments, templates, metrics, and compound growth workflows.

Generated with Printing Press 4.35.4 against Klaviyo API revision 2026-10-15. Every request sends `revision: 2026-10-15`.

At this revision, a campaign is a container. Messages carry status and send time; campaign-audiences carry included and excluded lists and segments; variations carry channel, template, subject, and sender. IDs issued before 2026-10-15 are now message IDs. Campaign workflows accept either a container ID or a historical campaign/message ID and resolve its audiences and variations. The raw `campaigns get-id` read expects a container ID and explains historical IDs on a 404.

Default local databases and response caches are scoped by a non-secret API-key fingerprint and honor XDG paths. Use an explicit `--db` only when intentionally selecting a tenant-specific store.

## Unique Capabilities

These capabilities aren't available in any other tool for this API.

### Campaign operations

- **`campaigns deploy`** - Create an email template and a campaign with an inline audience, message, and email variation, then verify that the result is an unscheduled draft.

  Repeat `--list-id` and `--segment-id` to include audiences; repeat `--exclude` for excluded list or segment IDs. `--preview-text`, `--reply-to`, and `--send-timezone` set the email preview, reply address, and timezone. The reply address defaults to the sender and the timezone defaults to the account timezone. Use `--template-file` for an HTML file or `--template-html` for inline HTML. Deployment never schedules or sends the campaign.

  ```bash
  klaviyo-pp-cli campaigns deploy --template-file ./email.html --campaign-name "Acme offer" \
    --list-id LIST_ID --list-id SECOND_LIST_ID --segment-id SEGMENT_ID --exclude EXCLUDED_ID \
    --subject "Acme offer" --preview-text "This week's offer" --from-email marketing@example.com \
    --from-label "Acme" --reply-to replies@example.com --send-timezone America/Chicago --json
  ```
- **`campaigns test-send`** - Run the same campaign checks as `plan qa-gate`, then send template previews for email variations to up to five recipients. Use it to review a draft in an inbox before launch; a failed QA verdict sends nothing.

  Repeat `--to` or use comma-separated addresses; without `--to`, recipients come from `KLAVIYO_TEST_SEND_TO`. `--variation-id` limits preview sends to one email variation while QA still checks the campaign. `--dry-run` runs QA and shows planned sends without sending. Preview POSTs are never retried; an ambiguous result says "unknown, check the inbox".

  `--brand` reads Klaviyo's brand kit (brand colors, logos, buttons, email defaults), warns on off-brand colors and old logos, and fails on a missing footer. Add `--brand-strict-neutrals` to flag grays that are not in the palette.

  ```bash
  klaviyo-pp-cli campaigns test-send --campaign-id CAMPAIGN_ID --to qa@example.com --json
  ```
- **`campaigns image-swap`** - Replace an image URL in every targeted email variation's template while preserving the rest of the draft.

  _Agents can make safe creative swaps without rebuilding a whole campaign._

  ```bash
  klaviyo-pp-cli campaigns image-swap --campaign-id CAMPAIGN_ID --old-url https://cdn.example.com/old.jpg --new-url https://cdn.example.com/new.jpg --json
  ```

- **`campaigns ab-test create`** - Add one to six subject-line alternatives to an unscheduled draft email message. The existing variation is A; new variations B through G share A's template and sender fields.

  Repeat `--subject` for each new variation. Preview text is copied from A unless `--preview-text` is repeated once per new subject. Empty subjects, duplicate subjects, scheduled messages and existing tests are refused. `--campaign-id` accepts a container with exactly one email message or a message ID; containers with several messages list the IDs to choose from.

  `--winner-metric` accepts `clicks` (default), `opens` or `orders`. `--test-percent` defaults to 20 and accepts 1 to 100; this share is split evenly across all variations, and the remaining share receives the winner. `--wait-hours` defaults to 4 and accepts 1 to 264. Apple Mail Privacy Protection inflates opens, so clicks or orders pick a truer winner.

  `--dry-run` reads current state and prints the plan without writing. Creates are attempted once; a failed create or settings update triggers best-effort deletion of this run's known new variations. An ambiguous create can leave an unconfirmed variation and reports that uncertainty. A successful command re-reads subjects, settings, draft status and send time. It never schedules or sends. Run `campaigns test-send --campaign-id acme-message-id` afterward to preview every variation.

  ```bash
  klaviyo-pp-cli campaigns ab-test create --campaign-id acme-message-id \
    --subject "Acme: a new way to start" --subject "Start with Acme today" \
    --preview-text "Your next step" --preview-text "See what's new" \
    --winner-metric clicks --test-percent 20 --wait-hours 4 --dry-run --json
  ```

- **`campaigns ab-test results`** - Read recipient counts, unique opens and clicks, rates, orders, revenue and revenue per recipient for each email variation. Unsent messages return `too_early` without querying reports. Missing variation rows produce zeros for available metrics.

  `--metric` accepts `clicks`, `opens` or `orders`; it defaults to the test's winner metric, then clicks. The rate leader must beat every other variation in a two-sided pooled two-proportion z-test with p < 0.05 for `clear_winner`; otherwise the verdict is `no_clear_winner`. P-values, an opens privacy note and small-sample notes (fewer than 100 selected metric events) accompany the result. When the winner audience share is positive, the most-mailed variation is labelled as a Klaviyo winner inferred from recipient counts.

  Reports use the day before the send date through now in `KLAVIYO_TIMEZONE` (default UTC), capped to the provider's 364-day window. `--conversion-metric-id` overrides the default Shopify Placed Order auto-resolution. If auto-resolution cannot find a usable order metric, clicks and opens use Received Email for reporting; orders, revenue and revenue per recipient are unavailable (`null` in JSON), with a note. Comparing orders requires a usable order metric. JSON includes message ID, A/B settings, timeframe, variations, verdict, leader, p-values and notes.

  ```bash
  klaviyo-pp-cli campaigns ab-test results --campaign-id acme-message-id --metric clicks --json
  ```

### Flow and form operations

- **`flows insert-step`** - Preview one new action after an existing flow action. Use `--step-file` for a JSON action definition without links, or `--stdin` to read it from stdin; add `--apply` to insert it once and verify placement.

  `--after` identifies the existing action. `--link` selects `next`, `next_if_true`, `next_if_false`, or a multi-branch branch ID. Unsupported step types are refused, and timing or logic steps in a live flow require `--allow-live-action`.

  ```bash
  klaviyo-pp-cli flows insert-step FLOW_ID --after ACTION_ID --step-file ./step.json --json
  ```
- **`forms publish`** - Review live-versus-draft changes and the last 30 days of views, submits, and submit rate before publishing a form. The default is a preview; `--apply` publishes and re-reads the form to verify its status.

  ```bash
  klaviyo-pp-cli forms publish FORM_ID --apply --json
  ```
- **`forms unpublish`** - Take a live form down after reviewing its draft and performance evidence. The default is a preview; `--apply` unpublishes and verifies the status.

  ```bash
  klaviyo-pp-cli forms unpublish FORM_ID --apply --json
  ```

Both form commands refuse a draft A/B test. `--dry-run` always previews, even with `--apply`; ambiguous publish or unpublish requests are never retried.

### Behavior graph analytics
- **`flow-decay`** - Identify flows whose open or click performance has decayed across recent time buckets using synced local data.

  _Agents can spot lifecycle automations that need refresh before revenue falls further._

  ```bash
  klaviyo-pp-cli flow-decay --days 90 --threshold 0.15 --json
  ```
- **`cohort`** - Group profiles by first event date and compute retention or repeat-action curves from synced profiles and events.

  _Agents can answer which acquisition cohorts keep buying without exporting CSVs._

  ```bash
  klaviyo-pp-cli cohort --metric "Placed Order" --interval month --json --select cohort,profiles,retained
  ```
- **`attribution`** - Join order events with campaign and flow attribution properties to summarize revenue by channel and source.

  _Agents can explain which automation or campaign generated revenue using local event evidence._

  ```bash
  klaviyo-pp-cli attribution --metric "Placed Order" --group-by flow --since 2026-01-01 --json
  ```

### Reporting

- **`send-budget`** - Compare email sends in the current billing period with the plan cap and scheduled email message recipient estimates. Use it before scheduling more sends; later periods are shown against the same cap, and missing estimates remain unknown rather than zero.

  Missing or stale estimates are refreshed with estimation jobs by default. `--wait` bounds that work (default two minutes); `--no-refresh` uses GET requests only.

  ```bash
  klaviyo-pp-cli send-budget --no-refresh --json
  ```
- **`campaign-values-reports`** - Query campaign performance with the required statistics, timeframe, and conversion metric request attributes. The conversion metric defaults to the account's Shopify Placed Order metric.

  ```bash
  klaviyo-pp-cli campaign-values-reports --timeframe last_12_months --statistics recipients,opens,clicks,conversion_value --agent
  ```
- **`report targeting`** - Resolve campaign audiences against both segments and lists, then join sends, attributed revenue, last-mailed dates, exclusions, and distinct never-mailed collections.

  ```bash
  klaviyo-pp-cli report targeting --timeframe last_12_months --agent
  ```

### Data hygiene
- **`list-quality-score`** - Score every list using API-valid collection fields plus paced per-list `profile_count` enrichment.

  ```bash
  klaviyo-pp-cli list-quality-score --json --no-cache
  ```
- **`segments get --with-counts`** - Enrich returned segments with current profile counts. The `list` alias has the same behavior. Add `--all` for every page; count requests are paced at Klaviyo's 1/s burst and 15/m steady limit and honor `Retry-After`.

  ```bash
  klaviyo-pp-cli segments get --all --with-counts --json --no-cache
  ```
- **`dedup`** - Find profiles that appear duplicated by email, phone, or cross-channel collisions in the local profile mirror.

  _Agents can flag customer records that split behavior and revenue history across identities._

  ```bash
  klaviyo-pp-cli dedup --by email,phone --json
  ```
- **`reconcile`** - Compare campaign UTM evidence with local Klaviyo order events and optional Shopify credentials when available.

  _Agents can check whether campaign performance agrees with order evidence before reporting numbers._

  ```bash
  klaviyo-pp-cli reconcile --campaign-id CAMPAIGN_ID --since 2026-01-01 --json
  ```

### Growth planning
- **`plan brief-to-strategy`** - Turn a growth brief into a structured Klaviyo campaign, flow, segment, and experiment strategy.

  _Agents can convert strategy notes into a concrete Klaviyo execution plan._

  ```bash
  klaviyo-pp-cli plan brief-to-strategy --brief ./brief.md --json
  ```
- **`plan qa-gate`** - Run a launch-readiness checklist for links, offers, dates, timezone, fallback tokens, unsubscribe placement, compliance, and deliverability flags.

  _Agents can block risky campaign launches with explicit findings instead of vague review notes._

  ```bash
  klaviyo-pp-cli plan qa-gate --campaign-id CAMPAIGN_ID --html ./email.html --json
  ```

  `--brand` reads Klaviyo's brand kit (brand colors, logos, buttons, email defaults), warns on off-brand colors and old logos, and fails on a missing footer. Add `--brand-strict-neutrals` to flag grays that are not in the palette.

## Command Reference

**accounts** - accounts

- `klaviyo-pp-cli accounts get` - Retrieve the account(s) associated with a given private API key. This will return 1 account object within the array....
- `klaviyo-pp-cli accounts get-id` - Retrieve a single account object by its account ID. You can only request the account by which the private API key...

**back-in-stock-subscriptions** - Manage back in stock subscriptions

- `klaviyo-pp-cli back-in-stock-subscriptions` - Subscribe a profile to receive back in stock notifications. Check out [our Back in Stock API...

**campaign-clone** - Manage campaign clone

- `klaviyo-pp-cli campaign-clone` - Clones an existing campaign, returning a new campaign based on the original with a new ID and name.<br><br>*Rate...

**campaign-message-assign-template** - Manage campaign message assign template

- `klaviyo-pp-cli campaign-message-assign-template` - Assign a non-reusable template copy to an email variation. `--data-id` is a variation ID, or a message ID with exactly one email variation. `--stdin` preserves the body while resolving the ID and checking unsubscribe links.

**campaign-messages** - Manage campaign messages

- `klaviyo-pp-cli campaign-messages get` - List campaign messages with optional filters. Messages carry status and send time; channel and content belong to variations.
- `klaviyo-pp-cli campaign-messages update` - Update a campaign message<br><br>*Rate limits*:<br>Burst: `10/s`<br>Steady: `150/m` **Scopes:** `campaigns:write`

**campaign-recipient-estimation-jobs** - Manage campaign recipient estimation jobs

- `klaviyo-pp-cli campaign-recipient-estimation-jobs get` - Retrieve the status of a recipient estimation job triggered with the `Create Campaign Recipient Estimation Job`...
- `klaviyo-pp-cli campaign-recipient-estimation-jobs refresh-campaign-recipient-estimation` - Trigger an asynchronous job to update the estimated number of recipients for the given campaign ID. Use the `Get...

**campaign-recipient-estimations** - Manage campaign recipient estimations

- `klaviyo-pp-cli campaign-recipient-estimations <id>` - Get the estimated recipient count for a campaign with the provided campaign ID. You can refresh this count by using...

**campaign-send-jobs** - Manage campaign send jobs

- `klaviyo-pp-cli campaign-send-jobs cancel-campaign-send` - Permanently cancel the campaign, setting the status to CANCELED or revert the campaign, setting the status back to...
- `klaviyo-pp-cli campaign-send-jobs get` - Get a campaign send job<br><br>*Rate limits*:<br>Burst: `10/s`<br>Steady: `150/m` **Scopes:** `campaigns:read`
- `klaviyo-pp-cli campaign-send-jobs send-campaign` - Trigger a campaign to send asynchronously<br><br>*Rate limits*:<br>Burst: `10/s`<br>Steady: `150/m` **Scopes:**...

**campaign-values-reports** - Manage campaign values reports

- `klaviyo-pp-cli campaign-values-reports` - Returns the requested campaign analytics values data<br><br>*Rate limits*:<br>Burst: `1/s`<br>Steady:...

**campaigns** - campaigns

Use `campaigns deploy` for an unscheduled email draft and `campaigns test-send` for QA followed by inbox previews. Use `campaigns ab-test create` for subject-line alternatives and `campaigns ab-test results` to compare their performance.

`campaigns create` translates legacy `--data-attributes-name` and `--data-attributes-campaign-messages` into the new definition, messages, and variations; a legacy audience object becomes one inline audience. `--stdin` bodies pass through unchanged and must already use the new model. The flags `--data-attributes-send-options`, `--data-attributes-send-strategy`, and `--data-attributes-tracking-options` were removed: put campaign `send_settings` in `--data-attributes-definition` and supported message settings (`is_add_utm`, `throttling_type`) in `--data-attributes-messages`.

- `klaviyo-pp-cli campaigns create` - Creates a campaign given a set of parameters, then returns it.<br><br>*Rate limits*:<br>Burst: `10/s`<br>Steady:...
- `klaviyo-pp-cli campaigns delete` - Delete a campaign with the given campaign ID.<br><br>*Rate limits*:<br>Burst: `10/s`<br>Steady: `150/m` **Scopes:**...
- `klaviyo-pp-cli campaigns get` - List campaign containers with optional filters. No channel filter is required or supported on this collection; read message status and send time from messages and channel from variations.
- `klaviyo-pp-cli campaigns get-id` - Read a campaign container by ID. A 404 explains that IDs from before 2026-10-15 are now message IDs.
- `klaviyo-pp-cli campaigns update` - Update a campaign with the given campaign ID.<br><br>*Rate limits*:<br>Burst: `10/s`<br>Steady: `150/m` **Scopes:**...

**catalog-categories** - Manage catalog categories

- `klaviyo-pp-cli catalog-categories create-catalog-category` - Create a new catalog category.<br><br>*Rate limits*:<br>Burst: `75/s`<br>Steady: `750/m` **Scopes:** `catalogs:write`
- `klaviyo-pp-cli catalog-categories delete-catalog-category` - Delete a catalog category using the given category ID.<br><br>*Rate limits*:<br>Burst: `75/s`<br>Steady: `750/m`...
- `klaviyo-pp-cli catalog-categories get` - Get all catalog categories in an account. Catalog categories can be sorted by the following fields, in ascending and...
- `klaviyo-pp-cli catalog-categories get-catalog-category` - Get a catalog category with the given category ID.<br><br>*Rate limits*:<br>Burst: `350/s`<br>Steady: `3500/m`...
- `klaviyo-pp-cli catalog-categories update-catalog-category` - Update a catalog category with the given category ID.<br><br>*Rate limits*:<br>Burst: `75/s`<br>Steady: `750/m`...

**catalog-category-bulk-create-jobs** - Manage catalog category bulk creat