Custom Objects Bulk Ingestion

You can import custom object records in bulk using two methods: SFTP and Data Warehouse Import (DWH). Both methods let you load raw records into a Data Source, which you then connect to a custom object type in the Klaviyo UI.

This article covers how each method works, how to format your files, and what to expect during and after import.


Before you begin

Familiarize yourself with custom objects, see Getting started with custom objects and Custom Objects API overview.

There are a few parts of the custom objects feature to keep in mind when configuring bulk ingestion / syncing:

  • A custom objects Data Source is a flexible, user-defined schema. A Data Source Record represents a record in a Data Source. Note these persist in Klaviyo, allowing you to create different schemas / objects in the future from Data Source Records you have loaded in the past.
  • A custom object itself consists of an object schema and a mapping schema between a Data Source and the object.
  • Different custom objects can be mapped to a single Data Source, using either the same or different field mappings.

To import custom objects from SFTP, you will need the ID of the data source where you want to create data source records. You can create this via API or in the web UI when creating a new custom object. Note this can also be created automatically during the first sync cycle of a data warehouse sync for custom objects.


Method 1: SFTP Import

Data source

Identify the custom objects data source ID you wish to target with the import, and create a config.json file with the ID, like this:

json
{
  "data_source_id": "01KTMWCZ8ZMNZS0HG5HQNX0H6E"
}

Directory structure

From the SFTP root, create a new folder in /imports/custom_objects/. The name of the folder does not affect how the data is processed.

Copy your config.json file, which contains data_source_id, into the new folder.

Place data files you wish to upload in the new folder. *.csv and *.jsonl files will be processed.

text
{company_id}/
  imports/
    profiles/           
    events/             
    custom_objects/     
      pets/            ← User-defined folder
     config.json        ← Configuration file with data_source_id
     pet_records.csv    ← CSV file to process
     pet_records.jsonl    ← JSONL file to process

Files placed directly under custom_objects/ without a subdirectory will be rejected. Every custom object import must be inside a named subfolder.

Supported file formats

Format

Extension

Notes

CSV

.csv

Column names must correspond to data source definition.

JSONL

.jsonl

One JSON object per line. Property names must correspond to data source definition. Nested objects and arrays are supported and stored as-is.

JSONL is strongly recommended when your records contain nested data or arrays.

CSV formatting

  • The first row must be a header row. Column names must correspond to the data source definition.
  • Nested JSON within a CSV cell must be double-quoted and internal quotes escaped with double-quote characters (e.g., "").
  • Empty cells are treated as absent fields, not null values.

Example CSV:

text
subscription_id,product_name,status,start_date
sub_001,Premium Plan,active,2025-01-15
sub_002,Basic Plan,inactive,2024-06-01

JSONL formatting

  • Each line must be a valid JSON object ({...}).
  • Lines that are not objects (e.g., arrays or primitives) are skipped and counted as errors.
  • Empty lines are silently ignored.
  • Nested objects and arrays are passed through and stored in full.

Example JSONL:

json
{"subscription_id": "sub_001", "product_name": "Premium Plan", "status": "active", "start_date": "2025-01-15"}
{"subscription_id": "sub_002", "product_name": "Basic Plan", "status": "inactive", "start_date": "2024-06-01", "metadata": {"source": "shopify", "tags": ["vip", "annual"]}}

What happens during import

  1. Klaviyo detects the subdirectory path and determines the resource type is custom_objects.
  2. Klaviyo checks if a custom objects data source with the data_source_id in config.json exists in the account.
  3. Records are extracted and processed in batches of up to 500 records per batch.
  4. Each batch is written to the data source via the same pipeline used by the Bulk API.
  5. You receive a completion notification (email or in-product) when the job finishes.

Error handling

  • Invalid rows (malformed CSV or unparseable JSONL lines) are skipped. The job continues processing the rest of the file.
  • The completion notification includes a count of skipped rows and a summary of any errors encountered.
  • If the folder has no .config.json or the data source ID in the config is invalid, the file will not be processed. To re-attempt, you must upload the file again with a different name. Old files will be removed after 30 days.

Method 2: Data Warehouse Import

Overview

If you use Snowflake, Databricks, or BigQuery, you can configure a data warehouse sync to import custom objects directly. The setup flow is the same as for profiles and events — connect your warehouse, select a table or view, and choose Custom Object as the resource type.

Configuring the sync

  1. Go to Integrations > Data Warehouse and open your warehouse connection.
  2. Create a new import sync or edit an existing one.
  3. Under Resource Type, select Custom Object.
  4. Select the Data Source you want to route records to.
    1. For an existing data source: data warehouse column names must match the data source definition.
    2. If no data source exists yet, one will be created automatically on the first sync run and named "Data Sync: {sync_name}". You can modify this name as you wish. Note that you will not be able to configure new objects until at least one record has been imported (in order to establish the data source schema).
  5. Save and activate the sync.

Sync behavior

  • Records are processed in batches of up to 500 per call.
  • Failed rows are written to a downloadable error file with row-level details (e.g., malformed values, missing identifiers).
  • Each sync run generates a log entry viewable in the sync's Logs tab, with details on extraction, transformation, load progress, and any errors.

After importing: if using an existing data source

If one or more custom objects are already configured with that data source, they will be created from the new data source records just as they would if you added data source records via API.

If no custom objects yet use that data source, use the New Object wizard to create a new object and select the data source used in your sync. Ensure at least one record has been imported so that the data source schema is established.

Was this article helpful?
Use this form only for article feedback. Learn how to contact support.

Explore more from Klaviyo

Community
Connect with peers, partners, and Klaviyo experts to find inspiration, share insights, and get answers to all of your questions.
Partners
Hire a Klaviyo-certified expert to help you with a specific task, or for ongoing marketing management.
Support

Access support through your account.

Email support (free trial and paid accounts) Available 24/7

Chat/virtual assistance
Availability varies by location and plan type