agentsclimarketplace

Klaviyo migration deep dive

Skill jeremylongshore/claude-code-plugins-plus-skills/plugins/saas-packs/klaviyo-pack/skills/klaviyo-migration-deep-dive

'Use when you are moving an email/CDP stack onto Klaviyo — off the deprecated v1/v2 APIs, off a competitor ESP (Mailchimp, SendGrid), or re-platforming gradually with the strangler fig pattern — and need field mapping, batch import, and post-migration validation.From its SKILL.md

Install
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill klaviyo-migration-deep-dive

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its file declares

Copied from the file, not written here

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

6.4 KB, ~1.4k tokens by cl100k_base, as published. Nobody here has run it

Klaviyo Migration Deep Dive

Overview

Comprehensive guide for migrating to Klaviyo from legacy APIs (v1/v2), competing ESPs (Mailchimp, SendGrid, etc.), or re-platforming with the strangler fig pattern. Covers data migration, API mapping, batch import, and post-migration validation.

This SKILL.md is the high-level workflow. The full, copy-paste code for every step lives in references/implementation.md; worked end-to-end scenarios live in references/examples.md.

Prerequisites

  • Target Klaviyo account configured
  • klaviyo-api SDK installed (npm install klaviyo-api)
  • Source system access for data export
  • Feature flag infrastructure (for gradual rollout)
  • Auth: a Klaviyo private API key (pk_***) exported as KLAVIYO_PRIVATE_KEY — used by the SDK's ApiKeySession. Legacy v1/v2 calls used a public token in the request body; the current REST API uses the private key in the session header. See references/implementation.md.

Migration Types

MigrationComplexityDurationRisk
Klaviyo v1/v2 to current APILow-Medium1-2 weeksLow
Mailchimp/SendGrid to KlaviyoMedium2-4 weeksMedium
Custom ESP to KlaviyoHigh4-8 weeksHigh
Full re-platformHigh2-3 monthsHigh

Instructions

Pick your migration type from the table above, then work the five steps. Each step has full code in references/implementation.md.

  1. Legacy v1/v2 to current API — replace deprecated track / identify / v2 subscribe HTTP calls with the klaviyo-api SDK (createOrUpdateProfile, createEvent, subscribeProfiles). The session skeleton every step builds on:

    import { ApiKeySession, ProfilesApi, EventsApi } from 'klaviyo-api';
    
    const session = new ApiKeySession(process.env.KLAVIYO_PRIVATE_KEY!);
    const profilesApi = new ProfilesApi(session);
    const eventsApi = new EventsApi(session);
    
  2. API field mapping — rename v1/v2 fields to the current schema: drop the $ prefix, camelCase everything ($first_namefirstName), and nest address fields under location. Full mapping table in references/implementation.md.

  3. Competitor migration — write a transform adapter that maps the competitor's contact shape to a Klaviyo profile, then batch-import (50 per batch) with Promise.allSettled, progress logging, and rate-limit delays. Skip suppressed/unsubscribed contacts.

  4. Strangler fig pattern — route traffic through a MigrationRouter behind a feature flag, ramping Klaviyo from 0% to 100% while optionally dual-writing for comparison.

  5. Post-migration validation — run validateMigration() to compare profile counts, sample data integrity, and list membership against the source before decommissioning the legacy system.

Full migration checklist (export → map → import → validate → cut over → decommission) is in references/implementation.md.

Output

Working through this skill produces:

  • Migrated code — v1/v2 HTTP calls replaced with klaviyo-api SDK calls, or a competitor-to-Klaviyo transform adapter plus a batch-import runner.
  • An import result{ imported, skipped, failed[] } from migrateContacts, with the failed list ready for a targeted retry.
  • A MigrationRouter (for gradual cutovers) that routes a configurable percentage of traffic to Klaviyo behind a feature flag.
  • A validation report{ passed, checks[] } from validateMigration covering profile count, data integrity, and list membership, used as the go/no-go gate before decommissioning the legacy system.

Error Handling

IssueCauseSolution
Duplicate profilesSame email imported twiceUse createOrUpdateProfile (upsert)
Phone format errorsNon-E.164 formatPre-validate and format to E.164 (+<countrycode><subscriber>)
Rate limited during importToo fastReduce batch size, add delays
Missing consent timestampsHistorical dataSet historicalImport: true flag
Template rendering errorsIncompatible template syntaxConvert to Klaviyo Django template syntax

Examples

Worked, end-to-end scenarios are in references/examples.md:

  • Mailchimp export → Klaviyo import — load a CSV, skip suppressed contacts, batch-import with progress output.
  • Cut over a v1 identify call to createOrUpdateProfile, showing the field renames.
  • Feature-flagged cutover — route 10% of events to Klaviyo while campaigns stay legacy.
  • Gate a deployment on a validateMigration pass.

Minimal first cutover — one profile upsert on the current API:

await profilesApi.createOrUpdateProfile({
  data: {
    type: 'profile',
    attributes: { email: '[email protected]', firstName: 'Jane', properties: { plan: 'pro' } },
  },
});

Resources

What ships with it: 2 files

12.8 KB alongside SKILL.md

references/

Keep looking

Skills are one crate of 326,144. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.