Klaviyo Developer
Expert-level guidance for building with the Klaviyo API — custom event tracking, profile management, SDK integration, webhooks, catalog sync, and data pipeline architecture.
For marketing strategy, flow auditing, segmentation, deliverability, and campaign optimization, see the klaviyo-analyst skill.
Install
git clone https://github.com/thatrebeccarae/claude-marketing.git && cp -r claude-marketing/skills/klaviyo-developer ~/.claude/skills/
MCP vs. SDK: When to Use Which
This skill is SDK-first by design — you're building production integrations against the Klaviyo API, not running ad-hoc queries. That said, Klaviyo's official MCP server is the right tool for parts of integration work, and you should know when to reach for it.
Use the SDK (klaviyo-api) when… |
Use the MCP (https://mcp.klaviyo.com/mcp) when… |
| Writing production event-tracking code |
Exploring an account's event schema before writing the integration |
| Building bulk import / sync pipelines |
Sanity-checking that events landed with the right property shape |
| Implementing webhook handlers |
Pulling a quick property inventory during integration design |
| Catalog sync jobs |
Inspecting flow trigger conditions while debugging why an event isn't firing a flow |
| Anything in CI, cron, or a deployed service |
Iterating on event schema design with the marketing analyst in the room |
The MCP wraps the same API this skill targets, so the schema rules, rate limits, and nesting constraints below apply equally to MCP-driven calls. The MCP is currently pinned to API revision 2026-04-15 — keep that in mind if you're versioning your own SDK code against an older revision.
For the full MCP tool inventory, OAuth setup, and read-only mode flag, see REFERENCE.md. For audit/analyst work, see the klaviyo-analyst skill — it's built around the MCP.
Core Capabilities
API Authentication & Versioning
- Private API key setup and key management best practices
- Public API key usage for client-side tracking (klaviyo.js)
- OAuth 2.0 authorization flow for third-party apps
- API revision headers and version lifecycle management
Custom Event Tracking
- Server-side event tracking via Events API
- Client-side tracking with klaviyo.js
- Event schema design and property naming conventions
- Idempotent event submission patterns
Profile Management
- Profile create, upsert, and bulk import patterns
- Custom property management and data types
- Subscription management (email, SMS consent)
- Profile merge and deduplication strategies
Webhooks
- Webhook subscription setup and event types
- Payload verification and signature validation
- Retry handling and idempotent webhook processing
SDK Usage & Libraries
- Python SDK (klaviyo-api)
- Node.js SDK (klaviyo-api-node)
- Ruby, PHP, and other community SDKs
- SDK initialization, error handling, and retry configuration
Catalog & Product Feed Sync
- Catalog item create/update/delete via API
- Category and variant management
- Product feed sync architecture for recommendations
- Handling large catalogs with bulk operations
Data Export & Warehouse Sync
- Metric aggregation API for reporting
- Profile and event export patterns
- Cursor-based pagination for large datasets
- ETL pipeline design for data warehouse integration
SDK Quick Reference
| Language |
Package |
Install |
| Python |
klaviyo-api |
pip install klaviyo-api |
| Node.js |
klaviyo-api |
npm install klaviyo-api |
| Ruby |
klaviyo-api-sdk |
gem install klaviyo-api-sdk |
| PHP |
klaviyo/api |
composer require klaviyo/api |
Rate Limits
| Endpoint Category |
Limit |
Window |
| Most endpoints |
75 requests |
per second |
| Bulk imports |
10 requests |
per second |
| Profile/Event create |
350 requests |
per second |
| Campaign send |
10 requests |
per second |
Headers returned: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
API Revision Timeline
| Revision |
Key Changes |
| 2026-01-15 |
Latest. Custom Objects Ingestion, Geofencing API (beta). |
| 2025-10-15 |
Forms API, Flow Actions API, SMS ROI reporting. |
| 2025-07-15 |
Mapped Metrics API, Custom Objects API (GA). |
| 2025-04-15 |
Web Feeds API, Custom Metrics, Push Token registration. |
| 2025-01-15 |
Reviews APIs, Flows Create API, Campaign image management. |
| 2024-10-15 |
Universal Content API, Form/Segment Reporting, Reviews API. |
| 2024-07-15 |
Forms API (retrieval), Webhooks API. |
| 2024-02-15 |
Reporting API, Create or Update Profile (upsert). |
Always include the revision header in API requests.
Essential Developer Checklist
- API key management — Store private keys in environment variables, never commit to source. Rotate keys periodically.
- Revision header — Always include
revision: YYYY-MM-DD header. Pin to a specific version.
- Rate limit handling — Implement exponential backoff with jitter on 429 responses.
- Idempotent events — Include a unique
unique_id property to prevent duplicate event tracking.
- Profile upserts — Use
POST /profiles/ with existing identifier for upsert behavior (creates or updates).
- Webhook verification — Validate webhook signatures before processing payloads.
- Pagination — Use cursor-based pagination for list endpoints. Never assume result counts.
- Error handling — Parse JSON:API error responses. Handle 4xx (client) and 5xx (server) differently.
- SDK initialization — Configure SDK with API key at app startup, not per-request.
- Testing — Use Klaviyo test/sandbox accounts. Mock API responses in unit tests.
Workflow: Custom Integration Setup
When building a custom Klaviyo integration:
- Define requirements — What events to track, what profile data to sync, what triggers are needed
- API key provisioning — Create a private API key with minimum required scopes
- Event schema design — Map business events to Klaviyo metric names and properties
- Profile sync strategy — Determine identifier (email vs phone vs external_id), upsert frequency
- Implement tracking — Server-side event tracking with proper error handling and retries
- Catalog sync (if applicable) — Product feed sync for recommendations and browse abandonment
- Webhook setup — Subscribe to relevant events, implement handler with signature verification
- Rate limit strategy — Queue and throttle API calls, implement backoff
- Monitoring — Log API errors, track event delivery rates, alert on failures
- Testing & validation — Verify events appear in Klaviyo, test flow triggers, validate profile data
Workflow: Integration Health Audit
When auditing an existing Klaviyo integration for health and data quality:
- Inventory active integrations — List all configured integrations (built-in and custom). Identify active vs stale connections.
- Map event sources — For each metric in the account, identify its source (built-in integration, custom API, Klaviyo-internal, form). Flag metrics with zero recent volume.
- Audit event schemas — Pull property structures for key events (Placed Order, Started Checkout, Viewed Product, Added to Cart). Check for:
- Missing standard properties (e.g.,
$value, ItemNames, line items)
- Duplicate/redundant metrics (e.g., "Placed Order" and "Order Placed" from different sources)
- Inconsistent property naming (camelCase vs snake_case across events)
- Check profile data pipeline — Verify profile properties are being synced correctly. Look for:
- Properties set by API vs properties set by events
- Stale properties (set once, never updated)
- Properties used in segmentation vs properties sitting unused
- Review catalog sync — Verify product catalog is synced and fresh. Check:
- Total catalog items vs expected product count
- Last sync timestamp
- Variant coverage (are variants synced or just parent products?)
- Category structure completeness
- Assess flow trigger architecture — Map how flows are triggered:
- Direct metric triggers (robust) vs segment-entry triggers via API-synced properties (brittle)
- Single points of failure (if API sync breaks, do all flows stop?)
- Trigger redundancy and fallback patterns
- Identify data accessibility gaps — Check for data that exists in event payloads but isn't usable:
- Nested objects in event properties (can use in templates, cannot use in segments/splits)
- Properties available in events but not synced to profiles (can't segment on them)
- Events tracked but not used in any flow or segment
- Produce integration health report — Document findings with severity ratings:
- Critical: Integration failures, broken event tracking, data loss
- High: Missing standard events, duplicate metrics, flow trigger fragility
- Medium: Unused events, incomplete catalog, stale profile properties
- Low: Naming inconsistencies, optimization opportunities
Event Schema Best Practices
Property Naming Conventions
- Use PascalCase for standard Klaviyo properties:
ProductName, ItemPrice, OrderId
- Use snake_case for custom properties:
business_type, account_id, reorder_count
- Never mix conventions within a single event — pick one and be consistent
- Prefix custom properties to avoid collision with Klaviyo-reserved names
Required Properties by Event
| Event |
Required Properties |
Revenue Property |
| Placed Order |
$value, OrderId, Items[] (line items) |
$value |
| Started Checkout |
$value, CheckoutURL, Items[] |
$value |
| Viewed Product |
ProductName, ProductID, URL, ImageURL |
— |
| Added to Cart |
$value, AddedItemProductName, AddedItemProductID, Items[] |
$value |
| Fulfilled Order |
$value, OrderId |
— |
Nesting Rules and Limitations
Klaviyo handles nested objects differently depending on where you access them:
| Context |
Access Level |
Example |
| Email/SMS templates |
Full access via Jinja — can loop over arrays, access nested properties |
{% for item in event.Items %}{{ item.ProductName }}{% endfor %} |
| Flow conditional splits |
Top-level properties ONLY — cannot access nested object fields |
Can split on event.OrderId, cannot split on event.Items[0].ProductName |
| Segments |
Top-level properties ONLY — cannot filter by nested object fields |
Can segment on "has done Placed Order where $value > 100", cannot segment on "where Items contains ProductName = X" |
| Flow triggers |
Top-level properties for trigger filters |
Same as conditional splits |
Workaround for nested data: If you need to segment or split on nested data, flatten it to top-level properties:
# Instead of relying on Items[] array for segmentation:
properties = {
"$value": 149.99,
"OrderId": "ORD-123",
"Items": [{"ProductName": "Wireless Headphones", "Category": "Electronics"}],
# Flatten for segmentation:
"ItemCategories": "Electronics,Accessories", # Comma-joined for "contains" filter
"HasElectronics": True, # Boolean flag for split
"TopItemCategory": "Electronics" # Top category for split
}
Custom Event Patterns (DTC / Subscription / Marketplace)
Additional events beyond the standard Shopify/e-commerce schema:
| Event Name |
Trigger |
Key Properties |
Account Created |
New account registered |
account_type, referral_source, signup_channel |
Subscription Started |
Recurring order activated |
$value, frequency, product_ids, plan_name |
Subscription Cancelled |
Recurring order stopped |
reason, plan_name, lifetime_charges |
Reorder Placed |
Repeat purchase of consumable |
$value, OrderId, days_since_last_order, reorder_items |
Wishlist Added |
Item saved for later |
ProductName, ProductID, Categories, Price |
Catalog Browsed |
Category/search activity |
category, search_term, results_count |
Sync key customer properties to profiles for segmentation:
profile_properties = {
"customer_type": "Subscriber",
"interests": ["Skincare", "Wellness"],
"subscription_plan": "Monthly Box",
"account_tier": "VIP",
"first_order_date": "2024-03-15",
"lifetime_order_count": 8,
"avg_order_value": 72.50,
"preferred_categories": ["Skincare", "Supplements"]
}
Data Accessibility Diagnosis
When data exists in Klaviyo but isn't usable where expected:
Symptoms
- "We track [event] but can't segment on [property]"
- "Flow split doesn't see the property we're sending"
- "Profile has the data but segment doesn't pick it up"
Root Causes and Solutions
| Symptom |
Root Cause |
Solution |
| Can't segment on event property |
Property is nested inside an array/object |
Flatten to top-level property on the event |
| Can't split flow on event property |
Property is nested |
Flatten, or use profile property instead |
| Segment doesn't match profiles |
Property is on events, not profiles |
Sync property to profile via API or "Update Profile Property" flow action |
| Profile property exists but segment empty |
Property value format mismatch (string "true" vs boolean true) |
Standardize data types in API sync |
| Event tracked but no flow triggers |
Metric name mismatch (case-sensitive) |
Verify exact metric name in Klaviyo matches API call |
| Flow triggers but filter excludes everyone |
Segment used as flow filter evaluates incorrectly |
Check segment conditions — may reference stale or incorrectly-typed properties |
Diagnosis Workflow
- Check metric exists: Use GET
/metrics/ to verify the event name appears
- Check event properties: Use GET
/events/?filter=... to pull recent events and inspect property structure
- Check profile properties: Use GET
/profiles/{id}/ to verify expected properties are on the profile
- Test segment conditions: Compare segment definition against actual profile data — look for type mismatches, case sensitivity issues
- Test flow trigger: Send a test event and trace whether the flow fires, where it stops, and why
How to Use This Skill
Ask me questions like:
- "How do I track a custom event from my Node.js backend?"
- "Help me set up a bulk profile import script"
- "What are Klaviyo's rate limits and how should I handle them?"
- "How do I verify Klaviyo webhook signatures?"
- "Set up catalog sync for my custom e-commerce platform"
- "How do I implement OAuth for a Klaviyo app?"
- "Design a data pipeline to export Klaviyo data to BigQuery"
- "Help me migrate from Klaviyo v1/v2 API to the current API"
- "Audit my integration — are events structured correctly?"
- "Why can't I segment on a property I'm tracking in events?"
Integration Examples
For complete integration patterns, worked examples with sample output, and code snippets, see EXAMPLES.md.
Scripts
The skill includes utility scripts for API interaction and integration management:
Developer Client
# Track a custom event
python scripts/klaviyo_client.py --action track-event \
--email user@example.com --event "Placed Order" \
--properties '{"value": 99.99, "OrderId": "ORD-123"}'
# Upsert a profile
python scripts/klaviyo_client.py --action upsert-profile \
--email user@example.com \
--properties '{"first_name": "Jane", "loyalty_tier": "Gold"}'
# List catalog items
python scripts/klaviyo_client.py --action catalog-items --format table
# Export profiles to CSV
python scripts/klaviyo_client.py --action export-profiles \
--max-pages 10 --format csv --output profiles.csv
Developer Tools
# Integration health check
python scripts/dev_tools.py --tool health-check
# Validate event tracking
python scripts/dev_tools.py --tool validate-events \
--events "Placed Order,Started Checkout,Viewed Product"
# Test webhook endpoint
python scripts/dev_tools.py --tool test-webhook \
--webhook-url https://example.com/webhooks/klaviyo
# Import profiles from CSV
python scripts/dev_tools.py --tool import-csv \
--file contacts.csv --list-id LIST_ID
# Export data with pagination
python scripts/dev_tools.py --tool export-data \
--resource profiles --max-records 5000 --output profiles.csv
The scripts handle API authentication, rate limiting, and JSON:API formatting. I'll help interpret results and provide implementation guidance.
Troubleshooting
Authentication Error: Verify that:
KLAVIYO_API_KEY is set as an environment variable or in a .env file
- The key starts with
pk_ (private API key, not public)
- The key has the required scopes for your operation (e.g.,
events:write for tracking, profiles:write for imports)
Rate Limit Errors (429): The SDK handles retries automatically (up to 3 retries with 60s max delay). If you still hit limits:
- Queue and throttle bulk operations (max 10 req/s for imports)
- Check
RateLimit-Remaining header proactively
- Implement exponential backoff with jitter for raw HTTP
Bulk Import Errors: Check that:
- Batch size does not exceed 10,000 profiles per job
- Email or phone is provided for each profile (at least one identifier)
- CSV column names match expected field names
Import Errors: Install required packages:
pip install klaviyo-api python-dotenv pandas
Security Notes
- Never hardcode API keys in code or commit them to version control
- Store keys in environment variables or
.env files
- Add
.env to .gitignore
- Use minimum required scopes — only enable write access where needed
- Rotate API keys periodically in Klaviyo Settings
- For OAuth integrations, store client secrets securely and refresh tokens before expiry
Data Privacy
This skill interacts with the Klaviyo API for integration development. When using write operations:
- Validate data before sending to avoid corrupting profile records
- Never log or store API keys, webhook secrets, or PII in plain text
- Use idempotency keys to prevent duplicate events
- Implement webhook signature verification to prevent spoofing
- Follow GDPR/CCPA requirements when handling profile data
- Use the Data Privacy Deletion endpoint for right-to-erasure requests
All operations are performed via the official Klaviyo API with proper authentication.
For detailed API endpoint reference, code patterns, authentication, and architecture diagrams, see REFERENCE.md.
For marketing strategy, flow optimization, and campaign auditing, use the klaviyo-analyst skill.
1---2name: klaviyo-developer3description: Klaviyo API and developer integration expertise. Event tracking, SDKs, webhooks, rate limits, OAuth, catalog sync, and code patterns. Use when the user asks about Klaviyo API, integrating with Klaviyo, tracking events, building custom integrations, webhook handling, or developer implementation. For marketing strategy, flow optimization, and campaign auditing, see the klaviyo-analyst skill.4license: MIT5---67# Klaviyo Developer89Expert-level guidance for building with the Klaviyo API — custom event tracking, profile management, SDK integration, webhooks, catalog sync, and data pipeline architecture.1011> For marketing strategy, flow auditing, segmentation, deliverability, and campaign optimization, see the **klaviyo-analyst** skill.1213## Install1415```bash16git clone https://github.com/thatrebeccarae/claude-marketing.git && cp -r claude-marketing/skills/klaviyo-developer ~/.claude/skills/17```1819## MCP vs. SDK: When to Use Which2021This skill is **SDK-first by design** — you're building production integrations against the Klaviyo API, not running ad-hoc queries. That said, Klaviyo's official MCP server is the right tool for parts of integration work, and you should know when to reach for it.2223| Use the **SDK** (`klaviyo-api`) when… | Use the **MCP** (`https://mcp.klaviyo.com/mcp`) when… |24|---|---|25| Writing production event-tracking code | Exploring an account's event schema before writing the integration |26| Building bulk import / sync pipelines | Sanity-checking that events landed with the right property shape |27| Implementing webhook handlers | Pulling a quick property inventory during integration design |28| Catalog sync jobs | Inspecting flow trigger conditions while debugging why an event isn't firing a flow |29| Anything in CI, cron, or a deployed service | Iterating on event schema design with the marketing analyst in the room |3031The MCP wraps the same API this skill targets, so the schema rules, rate limits, and nesting constraints below apply equally to MCP-driven calls. The MCP is currently pinned to API revision `2026-04-15` — keep that in mind if you're versioning your own SDK code against an older revision.3233For the full MCP tool inventory, OAuth setup, and read-only mode flag, see [REFERENCE.md](REFERENCE.md#mcp-server-reference). For audit/analyst work, see the **klaviyo-analyst** skill — it's built around the MCP.3435## Core Capabilities3637### API Authentication & Versioning38- Private API key setup and key management best practices39- Public API key usage for client-side tracking (klaviyo.js)40- OAuth 2.0 authorization flow for third-party apps41- API revision headers and version lifecycle management4243### Custom Event Tracking44- Server-side event tracking via Events API45- Client-side tracking with klaviyo.js46- Event schema design and property naming conventions47- Idempotent event submission patterns4849### Profile Management50- Profile create, upsert, and bulk import patterns51- Custom property management and data types52- Subscription management (email, SMS consent)53- Profile merge and deduplication strategies5455### Webhooks56- Webhook subscription setup and event types57- Payload verification and signature validation58- Retry handling and idempotent webhook processing5960### SDK Usage & Libraries61- Python SDK (klaviyo-api)62- Node.js SDK (klaviyo-api-node)63- Ruby, PHP, and other community SDKs64- SDK initialization, error handling, and retry configuration6566### Catalog & Product Feed Sync67- Catalog item create/update/delete via API68- Category and variant management69- Product feed sync architecture for recommendations70- Handling large catalogs with bulk operations7172### Data Export & Warehouse Sync73- Metric aggregation API for reporting74- Profile and event export patterns75- Cursor-based pagination for large datasets76- ETL pipeline design for data warehouse integration7778## SDK Quick Reference7980| Language | Package | Install |81|----------|---------|---------|82| Python | `klaviyo-api` | `pip install klaviyo-api` |83| Node.js | `klaviyo-api` | `npm install klaviyo-api` |84| Ruby | `klaviyo-api-sdk` | `gem install klaviyo-api-sdk` |85| PHP | `klaviyo/api` | `composer require klaviyo/api` |8687## Rate Limits8889| Endpoint Category | Limit | Window |90|-------------------|-------|--------|91| Most endpoints | 75 requests | per second |92| Bulk imports | 10 requests | per second |93| Profile/Event create | 350 requests | per second |94| Campaign send | 10 requests | per second |9596Headers returned: `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset`9798## API Revision Timeline99100| Revision | Key Changes |101|----------|-------------|102| 2026-01-15 | Latest. Custom Objects Ingestion, Geofencing API (beta). |103| 2025-10-15 | Forms API, Flow Actions API, SMS ROI reporting. |104| 2025-07-15 | Mapped Metrics API, Custom Objects API (GA). |105| 2025-04-15 | Web Feeds API, Custom Metrics, Push Token registration. |106| 2025-01-15 | Reviews APIs, Flows Create API, Campaign image management. |107| 2024-10-15 | Universal Content API, Form/Segment Reporting, Reviews API. |108| 2024-07-15 | Forms API (retrieval), Webhooks API. |109| 2024-02-15 | Reporting API, Create or Update Profile (upsert). |110111Always include the `revision` header in API requests.112113## Essential Developer Checklist1141151. **API key management** — Store private keys in environment variables, never commit to source. Rotate keys periodically.1162. **Revision header** — Always include `revision: YYYY-MM-DD` header. Pin to a specific version.1173. **Rate limit handling** — Implement exponential backoff with jitter on 429 responses.1184. **Idempotent events** — Include a unique `unique_id` property to prevent duplicate event tracking.1195. **Profile upserts** — Use `POST /profiles/` with existing identifier for upsert behavior (creates or updates).1206. **Webhook verification** — Validate webhook signatures before processing payloads.1217. **Pagination** — Use cursor-based pagination for list endpoints. Never assume result counts.1228. **Error handling** — Parse JSON:API error responses. Handle 4xx (client) and 5xx (server) differently.1239. **SDK initialization** — Configure SDK with API key at app startup, not per-request.12410. **Testing** — Use Klaviyo test/sandbox accounts. Mock API responses in unit tests.125126## Workflow: Custom Integration Setup127128When building a custom Klaviyo integration:1291301. **Define requirements** — What events to track, what profile data to sync, what triggers are needed1312. **API key provisioning** — Create a private API key with minimum required scopes1323. **Event schema design** — Map business events to Klaviyo metric names and properties1334. **Profile sync strategy** — Determine identifier (email vs phone vs external_id), upsert frequency1345. **Implement tracking** — Server-side event tracking with proper error handling and retries1356. **Catalog sync** (if applicable) — Product feed sync for recommendations and browse abandonment1367. **Webhook setup** — Subscribe to relevant events, implement handler with signature verification1378. **Rate limit strategy** — Queue and throttle API calls, implement backoff1389. **Monitoring** — Log API errors, track event delivery rates, alert on failures13910. **Testing & validation** — Verify events appear in Klaviyo, test flow triggers, validate profile data140141## Workflow: Integration Health Audit142143When auditing an existing Klaviyo integration for health and data quality:1441451. **Inventory active integrations** — List all configured integrations (built-in and custom). Identify active vs stale connections.1462. **Map event sources** — For each metric in the account, identify its source (built-in integration, custom API, Klaviyo-internal, form). Flag metrics with zero recent volume.1473. **Audit event schemas** — Pull property structures for key events (Placed Order, Started Checkout, Viewed Product, Added to Cart). Check for:148 - Missing standard properties (e.g., `$value`, `ItemNames`, line items)149 - Duplicate/redundant metrics (e.g., "Placed Order" and "Order Placed" from different sources)150 - Inconsistent property naming (camelCase vs snake_case across events)1514. **Check profile data pipeline** — Verify profile properties are being synced correctly. Look for:152 - Properties set by API vs properties set by events153 - Stale properties (set once, never updated)154 - Properties used in segmentation vs properties sitting unused1555. **Review catalog sync** — Verify product catalog is synced and fresh. Check:156 - Total catalog items vs expected product count157 - Last sync timestamp158 - Variant coverage (are variants synced or just parent products?)159 - Category structure completeness1606. **Assess flow trigger architecture** — Map how flows are triggered:161 - Direct metric triggers (robust) vs segment-entry triggers via API-synced properties (brittle)162 - Single points of failure (if API sync breaks, do all flows stop?)163 - Trigger redundancy and fallback patterns1647. **Identify data accessibility gaps** — Check for data that exists in event payloads but isn't usable:165 - Nested objects in event properties (can use in templates, cannot use in segments/splits)166 - Properties available in events but not synced to profiles (can't segment on them)167 - Events tracked but not used in any flow or segment1688. **Produce integration health report** — Document findings with severity ratings:169 - **Critical**: Integration failures, broken event tracking, data loss170 - **High**: Missing standard events, duplicate metrics, flow trigger fragility171 - **Medium**: Unused events, incomplete catalog, stale profile properties172 - **Low**: Naming inconsistencies, optimization opportunities173174## Event Schema Best Practices175176### Property Naming Conventions177- Use **PascalCase** for standard Klaviyo properties: `ProductName`, `ItemPrice`, `OrderId`178- Use **snake_case** for custom properties: `business_type`, `account_id`, `reorder_count`179- Never mix conventions within a single event — pick one and be consistent180- Prefix custom properties to avoid collision with Klaviyo-reserved names181182### Required Properties by Event183184| Event | Required Properties | Revenue Property |185|-------|-------------------|------------------|186| Placed Order | `$value`, `OrderId`, `Items[]` (line items) | `$value` |187| Started Checkout | `$value`, `CheckoutURL`, `Items[]` | `$value` |188| Viewed Product | `ProductName`, `ProductID`, `URL`, `ImageURL` | — |189| Added to Cart | `$value`, `AddedItemProductName`, `AddedItemProductID`, `Items[]` | `$value` |190| Fulfilled Order | `$value`, `OrderId` | — |191192### Nesting Rules and Limitations193194Klaviyo handles nested objects differently depending on where you access them:195196| Context | Access Level | Example |197|---------|-------------|---------|198| **Email/SMS templates** | Full access via Jinja — can loop over arrays, access nested properties | `{% for item in event.Items %}{{ item.ProductName }}{% endfor %}` |199| **Flow conditional splits** | Top-level properties ONLY — cannot access nested object fields | Can split on `event.OrderId`, cannot split on `event.Items[0].ProductName` |200| **Segments** | Top-level properties ONLY — cannot filter by nested object fields | Can segment on "has done Placed Order where $value > 100", cannot segment on "where Items contains ProductName = X" |201| **Flow triggers** | Top-level properties for trigger filters | Same as conditional splits |202203**Workaround for nested data**: If you need to segment or split on nested data, flatten it to top-level properties:204```python205# Instead of relying on Items[] array for segmentation:206properties = {207 "$value": 149.99,208 "OrderId": "ORD-123",209 "Items": [{"ProductName": "Wireless Headphones", "Category": "Electronics"}],210 # Flatten for segmentation:211 "ItemCategories": "Electronics,Accessories", # Comma-joined for "contains" filter212 "HasElectronics": True, # Boolean flag for split213 "TopItemCategory": "Electronics" # Top category for split214}215```216217### Custom Event Patterns (DTC / Subscription / Marketplace)218219Additional events beyond the standard Shopify/e-commerce schema:220221| Event Name | Trigger | Key Properties |222|------------|---------|----------------|223| `Account Created` | New account registered | `account_type`, `referral_source`, `signup_channel` |224| `Subscription Started` | Recurring order activated | `$value`, `frequency`, `product_ids`, `plan_name` |225| `Subscription Cancelled` | Recurring order stopped | `reason`, `plan_name`, `lifetime_charges` |226| `Reorder Placed` | Repeat purchase of consumable | `$value`, `OrderId`, `days_since_last_order`, `reorder_items` |227| `Wishlist Added` | Item saved for later | `ProductName`, `ProductID`, `Categories`, `Price` |228| `Catalog Browsed` | Category/search activity | `category`, `search_term`, `results_count` |229230Sync key customer properties to profiles for segmentation:231```python232profile_properties = {233 "customer_type": "Subscriber",234 "interests": ["Skincare", "Wellness"],235 "subscription_plan": "Monthly Box",236 "account_tier": "VIP",237 "first_order_date": "2024-03-15",238 "lifetime_order_count": 8,239 "avg_order_value": 72.50,240 "preferred_categories": ["Skincare", "Supplements"]241}242```243244## Data Accessibility Diagnosis245246When data exists in Klaviyo but isn't usable where expected:247248### Symptoms249- "We track [event] but can't segment on [property]"250- "Flow split doesn't see the property we're sending"251- "Profile has the data but segment doesn't pick it up"252253### Root Causes and Solutions254255| Symptom | Root Cause | Solution |256|---------|-----------|----------|257| Can't segment on event property | Property is nested inside an array/object | Flatten to top-level property on the event |258| Can't split flow on event property | Property is nested | Flatten, or use profile property instead |259| Segment doesn't match profiles | Property is on events, not profiles | Sync property to profile via API or "Update Profile Property" flow action |260| Profile property exists but segment empty | Property value format mismatch (string "true" vs boolean `true`) | Standardize data types in API sync |261| Event tracked but no flow triggers | Metric name mismatch (case-sensitive) | Verify exact metric name in Klaviyo matches API call |262| Flow triggers but filter excludes everyone | Segment used as flow filter evaluates incorrectly | Check segment conditions — may reference stale or incorrectly-typed properties |263264### Diagnosis Workflow2651. **Check metric exists**: Use GET `/metrics/` to verify the event name appears2662. **Check event properties**: Use GET `/events/?filter=...` to pull recent events and inspect property structure2673. **Check profile properties**: Use GET `/profiles/{id}/` to verify expected properties are on the profile2684. **Test segment conditions**: Compare segment definition against actual profile data — look for type mismatches, case sensitivity issues2695. **Test flow trigger**: Send a test event and trace whether the flow fires, where it stops, and why270271## How to Use This Skill272273Ask me questions like:274- "How do I track a custom event from my Node.js backend?"275- "Help me set up a bulk profile import script"276- "What are Klaviyo's rate limits and how should I handle them?"277- "How do I verify Klaviyo webhook signatures?"278- "Set up catalog sync for my custom e-commerce platform"279- "How do I implement OAuth for a Klaviyo app?"280- "Design a data pipeline to export Klaviyo data to BigQuery"281- "Help me migrate from Klaviyo v1/v2 API to the current API"282- "Audit my integration — are events structured correctly?"283- "Why can't I segment on a property I'm tracking in events?"284285## Integration Examples286287For complete integration patterns, worked examples with sample output, and code snippets, see [EXAMPLES.md](EXAMPLES.md).288289## Scripts290291The skill includes utility scripts for API interaction and integration management:292293### Developer Client294```bash295# Track a custom event296python scripts/klaviyo_client.py --action track-event \297 --email user@example.com --event "Placed Order" \298 --properties '{"value": 99.99, "OrderId": "ORD-123"}'299300# Upsert a profile301python scripts/klaviyo_client.py --action upsert-profile \302 --email user@example.com \303 --properties '{"first_name": "Jane", "loyalty_tier": "Gold"}'304305# List catalog items306python scripts/klaviyo_client.py --action catalog-items --format table307308# Export profiles to CSV309python scripts/klaviyo_client.py --action export-profiles \310 --max-pages 10 --format csv --output profiles.csv311```312313### Developer Tools314```bash315# Integration health check316python scripts/dev_tools.py --tool health-check317318# Validate event tracking319python scripts/dev_tools.py --tool validate-events \320 --events "Placed Order,Started Checkout,Viewed Product"321322# Test webhook endpoint323python scripts/dev_tools.py --tool test-webhook \324 --webhook-url https://example.com/webhooks/klaviyo325326# Import profiles from CSV327python scripts/dev_tools.py --tool import-csv \328 --file contacts.csv --list-id LIST_ID329330# Export data with pagination331python scripts/dev_tools.py --tool export-data \332 --resource profiles --max-records 5000 --output profiles.csv333```334335The scripts handle API authentication, rate limiting, and JSON:API formatting. I'll help interpret results and provide implementation guidance.336337## Troubleshooting338339**Authentication Error**: Verify that:340- `KLAVIYO_API_KEY` is set as an environment variable or in a `.env` file341- The key starts with `pk_` (private API key, not public)342- The key has the required scopes for your operation (e.g., `events:write` for tracking, `profiles:write` for imports)343344**Rate Limit Errors (429)**: The SDK handles retries automatically (up to 3 retries with 60s max delay). If you still hit limits:345- Queue and throttle bulk operations (max 10 req/s for imports)346- Check `RateLimit-Remaining` header proactively347- Implement exponential backoff with jitter for raw HTTP348349**Bulk Import Errors**: Check that:350- Batch size does not exceed 10,000 profiles per job351- Email or phone is provided for each profile (at least one identifier)352- CSV column names match expected field names353354**Import Errors**: Install required packages:355```bash356pip install klaviyo-api python-dotenv pandas357```358359## Security Notes360361- **Never hardcode** API keys in code or commit them to version control362- Store keys in environment variables or `.env` files363- Add `.env` to `.gitignore`364- Use **minimum required scopes** — only enable write access where needed365- Rotate API keys periodically in Klaviyo Settings366- For OAuth integrations, store client secrets securely and refresh tokens before expiry367368## Data Privacy369370This skill interacts with the Klaviyo API for integration development. When using write operations:371- Validate data before sending to avoid corrupting profile records372- Never log or store API keys, webhook secrets, or PII in plain text373- Use idempotency keys to prevent duplicate events374- Implement webhook signature verification to prevent spoofing375- Follow GDPR/CCPA requirements when handling profile data376- Use the Data Privacy Deletion endpoint for right-to-erasure requests377378All operations are performed via the official Klaviyo API with proper authentication.379380For detailed API endpoint reference, code patterns, authentication, and architecture diagrams, see [REFERENCE.md](REFERENCE.md).381382For marketing strategy, flow optimization, and campaign auditing, use the **klaviyo-analyst** skill.