io.tt SDK Docs
GuidesCRMKlaviyo

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 fieldKlaviyo profile attributeTypeFormat / Constraints
emailemailstringRequired — used as the primary profile identifier
firstNamefirstNamestringMax 255 chars
lastNamelastNamestringMax 255 chars
phoneNumberphoneNumber{ 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 fieldKlaviyo location propertyType
addressLine1address1string
addressLine2address2string
localitycitystring
countrycountrystring
administrativeDivisionregionstring
postalCodezipstring

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:

SourceKlaviyo property nameNotes
participant.id (io.tt)participant_idLinks the Klaviyo profile back to io.tt
uidparticipant_uidThe unique identifier passed in the signup call
Experience nameexperience_nameSet in the io.tt dashboard
Experience typeexperience_typee.g. competition, loyalty, gifting, golden_ticket
Brand namebrand_nameSet in the io.tt dashboard
marketingConsentmarketing_consentBoolean — also controls list subscription (see below)
profilingConsentprofiling_consentBoolean
dateOfBirthdate_of_birthISO 8601 string: YYYY-MM-DD
titletitlee.g. Mr., Ms.
extra.*Each key spread directlye.g. extra.ageRangeageRange property on the profile

Klaviyo treats profile creation and list subscription as two separate operations. io.tt handles both:

marketingConsent valueWhat io.tt does
trueCreates the Klaviyo profile and subscribes them to the experience's configured list with email.marketing.consent: SUBSCRIBED
false or omittedCreates 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 marketingConsent explicitly if your form collects it. Omitting it is treated the same as false.


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.

extra values must be strings or primitives. Nested objects are not supported for profile property mapping.


Notes

  • email is 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.
  • extra property 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.

On this page