Klaviyo Developer
This guide covers what you need to know as a developer implementing an io.tt experience that routes participant data into Klaviyo. It explains the field mapping, how custom properties work, and the consent behaviour.
For instructions on connecting Klaviyo to io.tt in the dashboard, see the Klaviyo Setup Guide (for brand admins).
For a general overview of CRM routing across all integrations, see the CRM Integration Guide.
How It Works (From Your Perspective)
No Klaviyo-specific code is required in your experience. Call the standard signup method for your experience type — the platform handles profile creation and list subscription server-side:
import { IOTT } from "@io-tt/sdk";
const sdk = new IOTT({ apiKey: process.env.IOTT_API_KEY });
await sdk.signupForCompetition(EXPERIENCE_ID, {
uid: userEmail,
email: userEmail,
firstName: "Jane",
lastName: "Smith",
marketingConsent: true,
extra: {
ageRange: "25-34",
productPreference: "single-malt",
},
});io.tt receives the registration and writes it to Klaviyo using the brand's configured API key and the experience's list ID. You do not configure this in code.
Field Mapping
These io.tt fields map to Klaviyo profile attributes and properties. The Type column reflects what the SDK expects from your code — Klaviyo field limits are noted where they constrain what you collect.
Klaviyo Profile Attributes
These fields map directly to standard Klaviyo profile attributes:
| io.tt field | Klaviyo profile attribute | Type | Format / Constraints |
|---|---|---|---|
email | email | string | Required — used as the primary profile identifier |
firstName | firstName | string | Max 255 chars |
lastName | lastName | string | Max 255 chars |
phoneNumber | phoneNumber | { countryCode: number; number: string } | Normalised to E.164 format (e.g. +447700900000) before being sent to Klaviyo |
Location (Address) Fields
Address fields are grouped into a Klaviyo location object on the profile:
| io.tt field | Klaviyo location property | Type |
|---|---|---|
addressLine1 | address1 | string |
addressLine2 | address2 | string |
locality | city | string |
country | country | string |
administrativeDivision | region | string |
postalCode | zip | string |
The location object is only included if at least one address field is provided. Individual address fields are omitted if empty.
Custom Profile Properties
These are written to Klaviyo's properties object on the profile, making them available for segmentation and personalisation:
| Source | Klaviyo property name | Notes |
|---|---|---|
participant.id (io.tt) | participant_id | Links the Klaviyo profile back to io.tt |
uid | participant_uid | The unique identifier passed in the signup call |
| Experience name | experience_name | Set in the io.tt dashboard |
| Experience type | experience_type | e.g. competition, loyalty, gifting, golden_ticket |
| Brand name | brand_name | Set in the io.tt dashboard |
marketingConsent | marketing_consent | Boolean — also controls list subscription (see below) |
profilingConsent | profiling_consent | Boolean |
dateOfBirth | date_of_birth | ISO 8601 string: YYYY-MM-DD |
title | title | e.g. Mr., Ms. |
extra.* | Each key spread directly | e.g. extra.ageRange → ageRange property on the profile |
Marketing Consent and List Subscription
Klaviyo treats profile creation and list subscription as two separate operations. io.tt handles both:
marketingConsent value | What io.tt does |
|---|---|
true | Creates the Klaviyo profile and subscribes them to the experience's configured list with email.marketing.consent: SUBSCRIBED |
false or omitted | Creates the Klaviyo profile only — the person is not subscribed to any list |
A profile is always created regardless of consent. This means the participant exists in Klaviyo (visible in your profile list) but is not reachable via list-based email campaigns until they grant consent.
Always pass
marketingConsentexplicitly if your form collects it. Omitting it is treated the same asfalse.
The extra Object
All signup methods accept an extra object for custom form data. Each key is spread directly into the Klaviyo profile's properties object:
await sdk.signupForCompetition(EXPERIENCE_ID, {
uid: userEmail,
email: userEmail,
marketingConsent: true,
extra: {
ageRange: "25-34", // → profile property: ageRange
productPreference: "whisky", // → profile property: productPreference
retailer: "harrods-london", // → profile property: retailer
},
});Unlike Salesforce, Klaviyo does not require pre-created fields — extra properties appear automatically on the profile. There is no naming restriction beyond Klaviyo's general property name limits.
extravalues must be strings or primitives. Nested objects are not supported for profile property mapping.
Notes
emailis required for the Klaviyo integration. If omitted, the integration will fail silently for that registration — io.tt will not surface this error to the consumer.- Phone numbers are normalised to E.164 format server-side using the country code and number you provide. An invalid combination (e.g. wrong country code for the number length) will result in the phone field being omitted from the profile.
extraproperty keys are passed through as-is without transformation. Use consistent, lowercase key names to keep your Klaviyo profile properties clean.- CRM routing is configured by io.tt staff — you do not specify the Klaviyo target in code.