Agent skill
klaviyo-data-handling
Implement Klaviyo data privacy, GDPR/CCPA compliance, and PII handling patterns. Use when handling profile data, implementing right-to-deletion, configuring data retention, or ensuring compliance with privacy regulations. Trigger with phrases like "klaviyo data", "klaviyo PII", "klaviyo GDPR", "klaviyo data retention", "klaviyo privacy", "klaviyo CCPA", "klaviyo delete profile", "klaviyo data privacy".
Install this agent skill to your Project
npx add-skill https://github.com/jeremylongshore/claude-code-plugins-plus-skills/tree/main/plugins/saas-packs/klaviyo-pack/skills/klaviyo-data-handling
SKILL.md
Klaviyo Data Handling
Overview
Handle profile data, PII, and privacy compliance with Klaviyo's Data Privacy API, GDPR right-to-deletion, CCPA requests, and safe logging patterns.
Prerequisites
klaviyo-apiSDK installed- API key with
data-privacy:writescope (for deletion requests) - Understanding of GDPR/CCPA requirements
- Audit logging infrastructure
Klaviyo Data Privacy API
Klaviyo provides a dedicated Data Privacy API for GDPR/CCPA profile deletion. When you delete a profile via this API, Klaviyo performs a full GDPR erasure -- the profile is permanently removed and cannot be recovered.
Instructions
Step 1: GDPR Profile Deletion (Right to Erasure)
import { ApiKeySession, DataPrivacyApi } from 'klaviyo-api';
const session = new ApiKeySession(process.env.KLAVIYO_PRIVATE_KEY!);
const dataPrivacyApi = new DataPrivacyApi(session);
/**
* Request profile deletion via Klaviyo's Data Privacy API.
* Accepts ONE identifier: email, phone_number, or profile ID.
* Providing multiple identifiers returns an error.
*
* WARNING: This is irreversible. Profile is permanently erased.
*/
async function requestProfileDeletion(identifier: {
email?: string;
phoneNumber?: string;
profileId?: string;
}): Promise<void> {
// Build the profile identifier (only ONE allowed)
const profileData: any = { type: 'profile' };
if (identifier.email) {
profileData.attributes = { email: identifier.email };
} else if (identifier.phoneNumber) {
profileData.attributes = { phone_number: identifier.phoneNumber };
} else if (identifier.profileId) {
profileData.id = identifier.profileId;
} else {
throw new Error('Must provide exactly one identifier: email, phoneNumber, or profileId');
}
await dataPrivacyApi.requestProfileDeletion({
data: {
type: 'data-privacy-deletion-job',
attributes: {
profile: { data: profileData },
},
},
});
// Audit log (required for compliance)
await auditLog({
action: 'GDPR_DELETION_REQUESTED',
identifier: identifier.email || identifier.phoneNumber || identifier.profileId!,
service: 'klaviyo',
timestamp: new Date().toISOString(),
});
console.log(`Deletion requested for ${JSON.stringify(identifier)}`);
}
// Usage
await requestProfileDeletion({ email: 'user-wants-deletion@example.com' });
Step 2: Data Subject Access Request (DSAR)
import { ProfilesApi, EventsApi, ListsApi } from 'klaviyo-api';
/**
* Export all Klaviyo data for a given profile (GDPR Article 15).
* Returns all profile attributes, event history, and list memberships.
*/
async function exportProfileData(email: string): Promise<{
profile: any;
events: any[];
lists: any[];
}> {
const profilesApi = new ProfilesApi(session);
const eventsApi = new EventsApi(session);
// 1. Get profile
const profiles = await profilesApi.getProfiles({
filter: `equals(email,"${email}")`,
});
const profile = profiles.body.data[0];
if (!profile) throw new Error(`No profile found for ${email}`);
// 2. Get profile's events
const events = await eventsApi.getEvents({
filter: `equals(profile_id,"${profile.id}")`,
sort: '-datetime',
});
// 3. Get profile's list memberships
const profileLists = await profilesApi.getProfileLists({ id: profile.id });
return {
profile: {
id: profile.id,
...profile.attributes,
},
events: events.body.data.map(e => ({
metric: e.attributes.metricId,
datetime: e.attributes.datetime,
properties: e.attributes.eventProperties,
})),
lists: profileLists.body.data.map(l => ({
id: l.id,
name: l.attributes.name,
})),
};
}
Step 3: PII Detection and Redaction in Logs
// src/klaviyo/pii.ts
const PII_PATTERNS = [
{ type: 'email', regex: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g },
{ type: 'phone', regex: /\+?\d{10,15}/g },
{ type: 'api_key', regex: /pk_[a-zA-Z0-9]{20,}/g },
];
export function redactPII(text: string): string {
let redacted = text;
for (const pattern of PII_PATTERNS) {
redacted = redacted.replace(pattern.regex, `[REDACTED:${pattern.type}]`);
}
return redacted;
}
export function redactObject(data: Record<string, any>): Record<string, any> {
const sensitiveFields = ['email', 'phoneNumber', 'phone_number', 'firstName', 'lastName', 'apiKey'];
const redacted = { ...data };
for (const field of sensitiveFields) {
if (redacted[field]) {
redacted[field] = typeof redacted[field] === 'string'
? `${redacted[field].substring(0, 3)}***`
: '[REDACTED]';
}
}
return redacted;
}
// Usage: safe logging of Klaviyo API responses
console.log('Profile data:', redactObject(profile.attributes));
Step 4: Consent Management
/**
* Record consent and subscribe to marketing.
* Always include consent timestamp for GDPR compliance.
*/
async function recordConsent(
email: string,
channels: { email?: boolean; sms?: boolean },
listId: string,
consentSource: string
): Promise<void> {
const subscriptions: any = {};
const now = new Date().toISOString();
if (channels.email) {
subscriptions.email = {
marketing: { consent: 'SUBSCRIBED', consentTimestamp: now },
};
}
if (channels.sms) {
subscriptions.sms = {
marketing: { consent: 'SUBSCRIBED', consentTimestamp: now },
};
}
await profilesApi.subscribeProfiles({
data: {
type: 'profile-subscription-bulk-create-job',
attributes: {
profiles: {
data: [{
type: 'profile' as any,
attributes: {
email,
subscriptions,
},
}],
},
historicalImport: false, // Set true for pre-existing consent
},
relationships: {
list: { data: { type: 'list', id: listId } },
},
},
});
await auditLog({
action: 'CONSENT_RECORDED',
identifier: email,
channels: Object.keys(channels).filter(c => channels[c as keyof typeof channels]),
source: consentSource,
timestamp: now,
});
}
Step 5: Audit Logging
// src/klaviyo/audit.ts
interface AuditEntry {
action: string;
identifier: string;
service: string;
timestamp: string;
details?: Record<string, any>;
}
async function auditLog(entry: AuditEntry): Promise<void> {
// Write to your audit database (must be retained per GDPR)
await db.auditLog.create({
data: {
...entry,
retainUntil: new Date(Date.now() + 7 * 365 * 24 * 60 * 60 * 1000), // 7 years
},
});
console.log(`[AUDIT] ${entry.action}: ${entry.identifier} at ${entry.timestamp}`);
}
Data Classification for Klaviyo
| Data Category | Examples in Klaviyo | Handling |
|---|---|---|
| PII | email, phoneNumber, firstName, lastName | Redact in logs, encrypt at rest |
| Sensitive | API keys, webhook secrets | Never log, rotate quarterly |
| Behavioral | Events, page views, purchases | Anonymize where possible |
| Marketing | List memberships, consent status | Audit trail required |
| Derived | Segments, predictive analytics | No special handling |
Error Handling
| Issue | Cause | Solution |
|---|---|---|
| Deletion request fails | Missing data-privacy:write scope |
Update API key scopes |
| Multiple identifiers error | Providing email AND phone | Use exactly one identifier |
| Profile not found for DSAR | Wrong email or already deleted | Search by ID or phone instead |
| PII in error logs | Unredacted API responses | Wrap logger with redactObject() |
Resources
Next Steps
For enterprise access control, see klaviyo-enterprise-rbac.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
dockerfile-generator
Dockerfile Generator - Auto-activating skill for DevOps Basics. Triggers on: dockerfile generator, dockerfile generator Part of the DevOps Basics skill category.
branch-naming-helper
Branch Naming Helper - Auto-activating skill for DevOps Basics. Triggers on: branch naming helper, branch naming helper Part of the DevOps Basics skill category.
readme-generator
Readme Generator - Auto-activating skill for DevOps Basics. Triggers on: readme generator, readme generator Part of the DevOps Basics skill category.
makefile-generator
Makefile Generator - Auto-activating skill for DevOps Basics. Triggers on: makefile generator, makefile generator Part of the DevOps Basics skill category.
gitignore-generator
Gitignore Generator - Auto-activating skill for DevOps Basics. Triggers on: gitignore generator, gitignore generator Part of the DevOps Basics skill category.
pre-commit-hook-setup
Pre Commit Hook Setup - Auto-activating skill for DevOps Basics. Triggers on: pre commit hook setup, pre commit hook setup Part of the DevOps Basics skill category.
Didn't find tool you were looking for?