Klaviyo 电商营销技能
加载方式:base.md + (typescript.md 或 python.md)
用于集成 Klaviyo 电子邮件/短信营销 - 客户档案、事件跟踪、活动、流程和细分。
参考资源: Klaviyo API 文档 | API 参考
为什么选择 Klaviyo
| 功能 |
好处 |
| 电商原生 |
为在线商店构建,深度集成 |
| 基于事件 |
从任何客户行为触发流程 |
| 细分 |
高级过滤行为+属性 |
| 电子邮件+短信 |
统一平台用于两个渠道 |
| 分析 |
按活动归因收入 |
API 基础
基础 URL
| 类型 |
URL |
| 服务器端(私有) |
https://a.klaviyo.com/api |
| 客户端(公共) |
https://a.klaviyo.com/client |
认证
// 服务器端:私有 API 密钥
const headers = {
"Authorization": "Klaviyo-API-Key pk_xxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
"revision": "2024-10-15", // API 版本
};
// 客户端:公共 API 密钥(6个字符)
const publicKey = "XXXXXX"; // 公司 ID
// 使用作为查询参数:?company_id=XXXXXX
API 密钥范围
| 范围 |
访问 |
| 只读 |
仅查看数据 |
| 完整 |
读写(默认) |
| 自定义 |
特定权限 |
安装
Node.js
npm install klaviyo-api
// lib/klaviyo.ts
import { ApiClient, EventsApi, ProfilesApi, ListsApi } from "klaviyo-api";
const client = new ApiClient();
client.setApiKey(process.env.KLAVIYO_PRIVATE_KEY!);
export const eventsApi = new EventsApi(client);
export const profilesApi = new ProfilesApi(client);
export const listsApi = new ListsApi(client);
Python
pip install klaviyo-api
# lib/klaviyo.py
from klaviyo_api import KlaviyoAPI
klaviyo = KlaviyoAPI(
api_key=os.environ["KLAVIYO_PRIVATE_KEY"],
max_delay=60,
max_retries=3
)
直接 HTTP(任何语言)
// lib/klaviyo.ts
const KLAVIYO_BASE_URL = "https://a.klaviyo.com/api";
async function klaviyoRequest(
endpoint: string,
method: "GET" | "POST" | "PATCH" | "DELETE" = "GET",
body?: object
) {
const response = await fetch(`${KLAVIYO_BASE_URL}${endpoint}`, {
method,
headers: {
Authorization: `Klaviyo-API-Key ${process.env.KLAVIYO_PRIVATE_KEY}`,
"Content-Type": "application/json",
revision: "2024-10-15",
},
body: body ? JSON.stringify(body) : undefined,
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Klaviyo API error: ${JSON.stringify(error)}`);
}
return response.json();
}
档案(客户)
创建/更新档案
// 插入档案(创建或更新)
async function upsertProfile(data: ProfileInput) {
return klaviyoRequest("/profiles", "POST", {
data: {
type: "profile",
attributes: {
email: data.email,
phone_number: data.phone, // E.164格式:+1234567890
first_name: data.firstName,
last_name: data.lastName,
properties: {
// 自定义属性
lifetime_value: data.ltv,
plan: data.plan,
signup_source: data.source,
},
location: {
city: data.city,
region: data.state,
country: data.country,
zip: data.zip,
},
},
},
});
}
# Python
def upsert_profile(data):
return klaviyo.Profiles.create_or_update_profile({
"data": {
"type": "profile",
"attributes": {
"email": data["email"],
"first_name": data["first_name"],
"last_name": data["last_name"],
"properties": {
"plan": data.get("plan"),
}
}
}
})
获取档案
async function getProfileByEmail(email: string) {
const response = await klaviyoRequest(
`/profiles?filter=equals(email,"${email}")`
);
return response.data[0];
}
async function getProfileById(profileId: string) {
return klaviyoRequest(`/profiles/${profileId}`);
}
更新档案属性
async function updateProfileProperties(
profileId: string,
properties: Record<string, any>
) {
return klaviyoRequest(`/profiles/${profileId}`, "PATCH", {
data: {
type: "profile",
id: profileId,
attributes: {
properties,
},
},
});
}
// 使用方法
await updateProfileProperties("profile_id", {
last_purchase_date: new Date().toISOString(),
total_orders: 5,
vip_status: true,
});
事件(跟踪)
跟踪事件(服务器端)
async function trackEvent(data: EventInput) {
return klaviyoRequest("/events", "POST", {
data: {
type: "event",
attributes: {
profile: {
data: {
type: "profile",
attributes: {
email: data.email,
// 或 phone_number, 或 external_id
},
},
},
metric: {
data: {
type: "metric",
attributes: {
name: data.eventName,
},
},
},
properties: data.properties,
value: data.value, // 用于收入跟踪
unique_id: data.uniqueId, // 去重
time: data.timestamp || new Date().toISOString(),
},
},
});
}
常见电商事件
// 查看产品
await trackEvent({
email: customer.email,
eventName: "Viewed Product",
properties: {
ProductID: product.id,
ProductName: product.name,
ProductURL: product.url,
ImageURL: product.image,
Price: product.price,
Categories: product.categories,
},
});
// 加入购物车
await trackEvent({
email: customer.email,
eventName: "Added to Cart",
properties: {
ProductID: product.id,
ProductName: product.name,
Quantity: quantity,
Price: product.price,
CartTotal: cart.total,
ItemNames: cart.items.map(i => i.name),
},
value: product.price * quantity,
});
// 开始结账
await trackEvent({
email: customer.email,
eventName: "Started Checkout",
properties: {
CheckoutURL: checkout.url,
ItemCount: cart.itemCount,
Categories: cart.categories,
ItemNames: cart.items.map(i => i.name),
},
value: cart.total,
});
// 下订单
await trackEvent({
email: customer.email,
eventName: "Placed Order",
properties: {
OrderId: order.id,
ItemCount: order.itemCount,
Categories: order.categories,
ItemNames: order.items.map(i => i.name),
Items: order.items.map(i => ({
ProductID: i.productId,
ProductName: i.name,
Quantity: i.quantity,
Price: i.price,
ImageURL: i.image,
ProductURL: i.url,
})),
BillingAddress: order.billingAddress,
ShippingAddress: order.shippingAddress,
},
value: order.total,
uniqueId: order.id, // 防止重复订单
});
// 履行订单
await trackEvent({
email: customer.email,
eventName: "Fulfilled Order",
properties: {
OrderId: order.id,
TrackingNumber: fulfillment.trackingNumber,
TrackingURL: fulfillment.trackingUrl,
Carrier: fulfillment.carrier,
},
});
// 取消订单
await trackEvent({
email: customer.email,
eventName: "Cancelled Order",
properties: {
OrderId: order.id,
Reason: cancellation.reason,
},
value: -order.total, // 退款用负值
});
客户端跟踪(JavaScript)
<!-- 添加到您的网站 -->
<script async src="https://static.klaviyo.com/onsite/js/klaviyo.js?company_id=XXXXXX"></script>
<script>
// 识别用户
klaviyo.identify({
email: "customer@example.com",
first_name: "John",
last_name: "Doe",
});
// 跟踪事件
klaviyo.track("Viewed Product", {
ProductID: "prod_123",
ProductName: "Blue T-Shirt",
Price: 29.99,
});
// 跟踪带价值
klaviyo.track("Added to Cart", {
ProductID: "prod_123",
ProductName: "Blue T-Shirt",
Price: 29.99,
$value: 29.99, // 收入跟踪
});
</script>
列表 & 细分
添加档案到列表
async function addToList(listId: string, emails: string[]) {
return klaviyoRequest(`/lists/${listId}/relationships/profiles`, "POST", {
data: emails.map(email => ({
type: "profile",
attributes: { email },
})),
});
}
// 按档案 ID
async function addProfileToList(listId: string, profileId: string) {
return klaviyoRequest(`/lists/${listId}/relationships/profiles`, "POST", {
data: [{ type: "profile", id: profileId }],
});
}
从列表中移除
async function removeFromList(listId: string, profileId: string) {
return klaviyoRequest(
`/lists/${listId}/relationships/profiles`,
"DELETE",
{
data: [{ type: "profile", id: profileId }],
}
);
}
获取列表成员
async function getListMembers(listId: string, cursor?: string) {
const params = new URLSearchParams({
"page[size]": "100",
});
if (cursor) {
params.set("page[cursor]", cursor);
}
return klaviyoRequest(`/lists/${listId}/profiles?${params}`);
}
创建列表
async function createList(name: string) {
return klaviyoRequest("/lists", "POST", {
data: {
type: "list",
attributes: { name },
},
});
}
活动
获取活动
async function getCampaigns(status?: "draft" | "scheduled" | "sent") {
const params = new URLSearchParams();
if (status) {
params.set("filter", `equals(status,"${status}")`);
}
return klaviyoRequest(`/campaigns?${params}`);
}
获取活动性能
async function getCampaignMetrics(campaignId: string) {
return klaviyoRequest(
`/campaign-recipient-estimations/${campaignId}`,
"GET"
);
}
流程(自动化)
获取流程
async function getFlows() {
return klaviyoRequest("/flows");
}
async function getFlowById(flowId: string) {
return klaviyoRequest(`/flows/${flowId}`);
}
常见流程触发器
| 流程类型 |
触发事件 |
| 欢迎系列 |
添加到列表 |
| 放弃购物车 |
加入购物车 + 无购买 |
| 浏览放弃 |
查看产品 + 无购物车 |
| 售后 |
下订单 |
| 赢回 |
X天内无订单 |
| 评论请求 |
履行订单 |
Webhooks
创建 Webhook
async function createWebhook(data: WebhookInput) {
return klaviyoRequest("/webhooks", "POST", {
data: {
type: "webhook",
attributes: {
name: data.name,
endpoint_url: data.url,
secret_key: data.secret,
topics: data.topics, // 例如 ["profile.created", "event.created"]
},
},
});
}
Webhook 主题
| 主题 |
触发 |
profile.created |
新档案创建 |
profile.updated |
档案属性更改 |
profile.merged |
档案合并 |
event.created |
新事件跟踪 |
list.member.added |
档案添加到列表 |
list.member.removed |
档案从列表中移除 |
验证 Webhook 签名
import crypto from "crypto";
function verifyKlaviyoWebhook(
payload: string,
signature: string,
secret: string
): boolean {
const expectedSignature = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("base64");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// Express 处理器
app.post("/webhooks/klaviyo", (req, res) => {
const signature = req.headers["klaviyo-webhook-signature"] as string;
if (!verifyKlaviyoWebhook(JSON.stringify(req.body), signature, WEBHOOK_SECRET)) {
return res.status(401).json({ error: "Invalid signature" });
}
const { type, data } = req.body;
switch (type) {
case "profile.created":
handleNewProfile(data);
break;
case "event.created":
handleNewEvent(data);
break;
}
res.status(200).json({ received: true });
});
速率限制
| 窗口 |
限制 |
| 突发 |
每秒75个请求 |
| 稳定 |
每分钟700个请求 |
处理速率限制
async function klaviyoRequestWithRetry(
endpoint: string,
method: "GET" | "POST" | "PATCH" | "DELETE" = "GET",
body?: object,
retries = 3
): Promise<any> {
for (let attempt = 0; attempt < retries; attempt++) {
const response = await fetch(`${KLAVIYO_BASE_URL}${endpoint}`, {
method,
headers: {
Authorization: `Klaviyo-API-Key ${process.env.KLAVIYO_PRIVATE_KEY}`,
"Content-Type": "application/json",
revision: "2024-10-15",
},
body: body ? JSON.stringify(body) : undefined,
});
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get("Retry-After") || "5");
await new Promise(r => setTimeout(r, retryAfter * 1000));
continue;
}
if (!response.ok) {
throw new Error(`Klaviyo error: ${response.status}`);
}
return response.json();
}
throw new Error("Max retries exceeded");
}
分页
async function getAllProfiles() {
const profiles = [];
let cursor: string | undefined;
do {
const params = new URLSearchParams({ "page[size]": "100" });
if (cursor) {
params.set("page[cursor]", cursor);
}
const response = await klaviyoRequest(`/profiles?${params}`);
profiles.push(...response.data);
cursor = response.links?.next
? new URL(response.links.next).searchParams.get("page[cursor]")
: undefined;
} while (cursor);
return profiles;
}
过滤 & 排序
// 按日期过滤
const recentEvents = await klaviyoRequest(
`/events?filter=greater-than(datetime,2024-01-01T00:00:00Z)`
);
// 按属性过滤
const vipProfiles = await klaviyoRequest(
`/profiles?filter=equals(properties.vip_status,true)`
);
// 多个过滤器(AND)
const filtered = await klaviyoRequest(
`/profiles?filter=and(equals(properties.plan,"pro"),greater-than(properties.ltv,1000))`
);
// 排序
const sorted = await klaviyoRequest(
`/profiles?sort=-created` // 按创建日期降序
);
// 稀疏字段集(仅返回特定字段)
const sparse = await klaviyoRequest(
`/profiles?fields[profile]=email,first_name,properties`
);
集成模式
电商订单同步
// 下订单后
async function syncOrderToKlaviyo(order: Order) {
// 1. 插入客户档案
await upsertProfile({
email: order.customerEmail,
firstName: order.customerFirstName,
lastName: order.customerLastName,
phone: order.customerPhone,
});
// 2. 更新生命周期指标
await updateProfileProperties(
await getProfileIdByEmail(order.customerEmail),
{
last_order_date: new Date().toISOString(),
total_orders: order.customerOrderCount,
lifetime_value: order.customerLifetimeValue,
}
);
// 3. 跟踪订单事件
await trackEvent({
email: order.customerEmail,
eventName: "Placed Order",
properties: {
OrderId: order.id,
Items: order.items,
// ... 其他属性
},
value: order.total,
uniqueId: order.id,
});
}
订阅状态同步
// 当订阅更改时
async function syncSubscriptionStatus(user: User, status: string) {
await updateProfileProperties(user.klaviyoProfileId, {
subscription_status: status,
subscription_plan: user.plan,
subscription_updated_at: new Date().toISOString(),
});
await trackEvent({
email: user.email,
eventName: `Subscription ${status}`,
properties: {
plan: user.plan,
mrr: user.mrr,
},
value: status === "cancelled" ? -user.mrr : user.mrr,
});
}
环境变量
# .env
KLAVIYO_PRIVATE_KEY=pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
KLAVIYO_PUBLIC_KEY=XXXXXX
KLAVIYO_WEBHOOK_SECRET=your_webhook_secret
添加到 credentials.md:
'KLAVIYO_PRIVATE_KEY': r'pk_[a-f0-9]{32}',
'KLAVIYO_PUBLIC_KEY': r'[A-Z0-9]{6}',
清单
设置
- [ ] 创建 Klaviyo 账户
- [ ] 生成私有 API 密钥
- [ ] 记录公共 API 密钥(公司 ID)
- [ ] 在头文件中设置 API 版本
集成
- [ ] 注册/更新时同步档案
- [ ] 跟踪关键事件(查看、购物车、订单)
- [ ] 订单事件包括项目数组
- [ ] 收入跟踪与 $value
- [ ] 唯一 ID 用于去重
测试
- [ ] 测试档案创建
- [ ] 测试事件跟踪
- [ ] 在 Klaviyo 仪表板中验证事件
- [ ] 测试 webhook 交付
- [ ] 测试速率限制处理
反模式
- 缺少电子邮件/电话 - 每个档案至少需要一个标识符
- 重复事件 - 使用 unique_id 为订单/交易去重
- 缺少项目数组 - 产品推荐所需
- 仅限客户端 - 服务器端跟踪更可靠
- 忽略速率限制 - 实施指数退避
- 硬编码 API 密钥 - 使用环境变量
- 缺少收入跟踪 - 包括 $value 用于 ROI 归因