# Klaviyo in a lifecycle audit

Where each audit area lives in Klaviyo, how to read it without write access, and the behaviour that changes a finding. Facts were read on 2026-11-01 (the custom integration FAQ and the MCP tool list on 2026-11-02) from the Klaviyo pages in `sources.yaml` unless marked "verify live".

## Read-only access

- Remote MCP server through a custom connector with both controls in the URL:
  `https://mcp.klaviyo.com/mcp?read-only=true&disable-tools-with-user-generated-content=true`
  The first parameter disables write tools; the second disables the tools Klaviyo designates as reading user-generated content. Directory-listed connectors and apps cannot take URL parameters, so add a custom connector with this URL.
- The connecting user needs the Owner, Admin or Manager role.
- Local server alternative: `READ_ONLY=true`, with a private API key the user sets in their own environment. Never paste a key into chat.
- After connecting, list the tools and confirm no write tool is present. Run `get_account_details` first and stop if the account is not the one the user named (account mix-ups are the common failure with several stores).
- Read tools for the audit: `get_account_details`, `get_flows`, `get_flow`, `get_flow_message`, `get_flow_action`, `get_flow_report`, `get_campaigns`, `get_campaign`, `get_campaign_message`, `get_campaign_report`, `get_segments`, `get_segment`, `get_lists`, `get_list`, `get_flows_triggered_by_segment`, `get_flows_triggered_by_list`, `get_flows_triggered_by_metric`, `get_metrics`, `get_metric`, `query_metric_aggregates`.
- `get_flows_triggered_by_metric` lists every flow on one metric, the JC07 collision check. `get_sending_domains` lists sending domains for the DL01 sender inventory. It is marked Beta, meaning it uses a beta API revision and may change. Klaviyo's tool list does not mark it as needing `beta=true`, so leave that parameter off (checked 2026-11-06). If the tool is missing, read sending domains in the UI.
- Do not call profile tools such as `get_profiles` or `get_profile`; they return personal data. Consent and suppression are read as segment counts, never person by person.

## Where each area lives

- Journey coverage: flows with their trigger (metric, list, segment, date, price drop), trigger filters and profile filters; campaigns for recurring sends. `get_flows_triggered_by_segment` and `get_flows_triggered_by_list` find hidden entry paths.
- Caps: Smart Sending per campaign and per flow message.
- Preferences: email and SMS consent per profile (read as segment counts), suppression, list membership.
- Measurement: attribution model and windows in account settings; click tracking settings.
- Send log and entry counts: flow and campaign reports, metric aggregates.

## Behaviour that changes findings

- Smart Sending defaults: email 16 hours, SMS 24 hours, push 24 hours; channels independent; skipped messages are not rescheduled; transactional messages are never skipped; on by default for campaigns but not for every flow message; window changes are not retroactive; a marketing send with Smart Sending off resets each attempted recipient's timer (FC02, FC06).
- Metric trigger filters apply only at entry; profile filters apply at entry and before every action, and a failed profile filter skips the action while the person can continue (JC02, JC05).
- A flow trigger cannot be changed after it is set; fixing it means a copied flow and a history reset. Opens and clicks cannot trigger flows. Only top-level event properties work as trigger filters.
- Re-entry options and how each applies per trigger type: verify live before rating JC06.
- Events API: dedupes on profile, metric and `unique_id`; same-second events without one collide; `backfill: true` records events without triggering metric flows (TD03, TD04). Klaviyo does not accept @example.com addresses into its event or profile processing (custom integration FAQ), so seeds need real controlled mailboxes.
- Consent: SUBSCRIBED, NEVER_SUBSCRIBED, UNSUBSCRIBED; implied consent stays NEVER_SUBSCRIBED; list membership does not change consent; suppression is separate; SMS consent must be explicit (PC05, PC08).
- Attribution: last-touch by default; Advanced KDP and Personalization customers can select linear. New-account default windows and recalculation: see measurement-and-holdouts.md. Flow revenue share is credit, not lift (MH01).
- Click tracking can be off per account, recipient or link, and click-tracking consent is separate from marketing consent, so a missing click is not proof of disinterest (SG02).

## Exports for the scripts

- Entry and send counts for the inventory: `get_flow_report` and `get_campaign_report`, or `query_metric_aggregates` on the received-message metric per flow, for the window.
- Send log: metric events for sends, bounces and unsubscribes through the API or an export (verify the current metric names live), hashed in the warehouse.
- Preference log: consent change events with their method or source, mapped to the script's source names.

## Verify live

Holdout and control group options for flows and campaigns, click tracking consent behaviour, current flow report fields, flow message status labels (JC09), re-entry options per trigger type, and the MCP tool list after connecting.
