How to Upload Profile CSVs to Klaviyo's SFTP Import Tool

Load customers into Klaviyo in bulk through Klaviyo's SFTP import tool: build a correctly formatted profiles CSV from your store, ERP or database, and upload it to Klaviyo's SFTP server on a schedule.

What This Integration Does

Klaviyo offers an SFTP import tool for large or regular profile and event loads: you connect to Klaviyo's SFTP server with an SSH key and drop a CSV into its profiles or events folder, and Klaviyo ingests it as an import job. It is the efficient route for thousands of profiles at a time, such as a nightly loyalty export from your ERP or POS. The part that takes effort is producing the CSV in Klaviyo's exact format and getting it onto the server reliably. This Spojit workflow does both: it reads the source records, maps them to Klaviyo's headers, builds the CSV, and uploads it with the FTP / SFTP connector using your SSH key.

Each run uploads one timestamped file. Klaviyo ingests every file in the folder, including duplicates, so unique names matter; re-running the workflow uploads a new file and Klaviyo updates the same profiles again, which is harmless because profiles are matched on email, phone number or external ID.

Prerequisites

  • SFTP access set up in Klaviyo: you generate an SSH key pair, add the public key (OpenSSH format) in Klaviyo's SFTP settings, and Klaviyo shows the host and username to connect with.
  • An FTP / SFTP connection in Spojit: Protocol sftp, the host, port 22, the username from Klaviyo, and your private key.
  • A source for the profiles, such as a MySQL query, a NetSuite SuiteQL query or a Shopify customer list.

Step 1: Schedule Trigger

Add a Trigger node with type Schedule, for example 0 1 * * * for a nightly load.

Step 2: Read the Source Profiles

Add the step that returns your records. For a database: a MySQL step with execute-query, such as SELECT email, first_name, last_name, phone, loyalty_tier, points FROM customers WHERE updated_at >= NOW() - INTERVAL 1 DAY. Name the output source.

Step 3: Map to Klaviyo's CSV Headers

Add a Transform with Iterate over set to the rows, producing objects whose keys are Klaviyo's headers:

{
  "Email": "{{ item.email }}",
  "First Name": "{{ item.first_name }}",
  "Last Name": "{{ item.last_name }}",
  "PhoneNumber": "{{ item.phone }}",
  "Profile.loyalty_tier": "{{ item.loyalty_tier }}",
  "Profile.loyalty_points": "{{ item.points }}"
}

Each row needs at least one identifier: Email, PhoneNumber or ExternalID. Custom properties use the Profile. prefix. To subscribe people to an email list in the same import, add a List ID column (a valid email is then required on that row) and, if you have consent, Email Marketing Consent set to SUBSCRIBED with its timestamp column.

Step 4: Build the CSV

Add a Connector node on CSV Tools with from-json, data set to the mapped rows, header on and the delimiter ,. CSV Tools quotes values that contain commas or quotes, which Klaviyo requires. Name the output csv.

Step 5: Upload to the Profiles Folder

Add a Connector node on FTP / SFTP with upload-file:

  • path: /profiles/profiles-{{ run_stamp.result }}.csv, where run_stamp is the run time formatted as YYYYMMDD-HHmmss with the Date & Time format tool.
  • content: the CSV text from Step 4.

Klaviyo starts an import job for the file. Its progress, and any rows it skipped, appear in Klaviyo under the Data import tab in Recent Imports, and Klaviyo emails you when a job succeeds or fails.

Step 6: Notify on Large or Failed Loads (Optional)

Add a Condition on the source row count and send a Slack message when the count is zero (the source query may have broken) or unusually large. Upload errors from the SFTP step fail the run, which Spojit's run history and notifications already surface.

Tips

  • Events too: the events folder takes event CSVs with Metric name, Time (ISO 8601) and a profile identifier such as Profile.Email, plus optional Value and Unique ID. Upload POS purchases as events this way.
  • Test small: Klaviyo recommends starting with a file of a few rows. Upload one manually first and check the import job before automating.
  • API instead for small, real-time changes: for one profile at a time (a signup, a form fill), the Klaviyo connector's create-profile and add-profiles-to-list tools are immediate; SFTP suits batches.
  • Only changed rows: filter the source query to rows updated since the last run so each file stays small and imports finish quickly.

Common Pitfalls

  • Wrong key format: Klaviyo needs an OpenSSH public key. Keys in other formats (such as SSH2 from some tools) must be converted before adding them.
  • Header spelling: headers must match Klaviyo's names exactly (PhoneNumber, First Name). A misspelt header becomes a custom property instead of filling the standard field.
  • Phone formats: phone numbers must be in a format Klaviyo accepts (E.164 such as +61400000000 is safest), and phone-only rows need SMS enabled in the account.
  • Row size: no row may exceed 1 MB. Keep long text fields out of the import.

Testing

Limit the source query to three test customers, run the workflow manually, and watch the import job in Klaviyo's Recent Imports. Open the three profiles and check the standard fields and custom properties, then remove the limit and turn the schedule on.

Learn More

Ready to build this?

Start on the free plan: 500 AI credits a month, no card needed.

Start free

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.