Skip to content

Commit 42598d2

Browse files
Klaviyo: configurable batch size (#3650)
* Make Klaviyo batch_size configurable in UI - Set unsafe_hidden to false to make batch_size visible in UI - Add minimum constraint of 100 to prevent too-small batches - Add maximum constraint of 10,000 (Klaviyo API limit) - Update description with recommendations for RETL sources (500-1000) and event streams (5000-10000) This enables customers to adjust batch sizes for their specific use cases, particularly RETL sources that may need smaller batch sizes to avoid payload rejections. * Add batch_bytes field to Klaviyo batching actions - Add batch_bytes to properties.ts with 5MB max (Klaviyo API limit) - Add batch_bytes to all actions using profile-bulk-import-jobs API: - upsertProfile - addProfileToList - trackEvent - removeProfile - removeProfileFromList - Default: 4MB to stay safely below 5MB limit - Note known RETL limitations in field description * Keep batch_bytes hidden (unsafe_hidden: true) batch_bytes has known limitations with RETL and generally should not be exposed to customers per framework guidance. Only batch_size needs to be visible. * Remove batch_bytes from actions not using profile-bulk-import-jobs API batch_bytes with 5MB limit only applies to profile-bulk-import-jobs API. Removed from: - trackEvent (uses event-bulk-create-jobs API) - removeProfile (uses DELETE operations) - removeProfileFromList (uses DELETE operations) batch_bytes remains only in: - upsertProfile (uses profile-bulk-import-jobs) - addProfileToList (uses profile-bulk-import-jobs) * Fix: Remove batch_bytes from addProfileToList perform method batch_bytes is only used by platform batching layer, not in single-event perform method * Fix: Exclude batch_bytes from upsertProfile API payload batch_bytes and batch_size are platform-level batching controls and should not be sent to Klaviyo API as profile attributes * Remove min/max constraints from batch_size and batch_bytes Test data generator doesn't respect min/max constraints, and no other destination uses them for batch fields. The field descriptions already document recommended values and Klaviyo's limits (10K profiles, 5MB payload). * Update test data generator to respect min/max constraints Modified test-data.ts to: - Accept minimum/maximum parameters in setTestData function - Use Chance.js min/max options when generating integer/number values - Pass minimum/maximum from field definitions through all callers Re-added min/max constraints to Klaviyo batch fields: - batch_size: min 100, max 10000 - batch_bytes: min 100000, max 5000000 This ensures generated test data respects field validation constraints. * Update generated types for Klaviyo batch field constraints * Fix timezone-based test failures in snapshot tests Apply deterministic UTC timestamp generation for date-time fields to avoid CI failures due to timezone differences between local and CI environments. This fixes Braze ecommerceSingleProduct snapshot test failures. Credit: Adapted from commit 4664041 by Sayan Das * Remove min/max from hidden batch_bytes field and simplify batch_size description - Remove minimum/maximum constraints from batch_bytes (field is hidden, constraints not needed) - Simplify batch_size description to match standard pattern - Keep batch_size default at 10000 with min/max constraints (100-10000) * update types * Remove batch_bytes field - platform default of 4MB is sufficient Co-Authored-By: Claude Opus 4.6 <[email protected]> * Set minimum to 100 for all * Fix test-data min/max handling and revert timezone workaround - Use conditional spread in setTestData to avoid passing undefined min/max to chance - Revert date-time generation back to chance.date().toISOString() - Revert braze snapshot to original values - Document TZ=UTC requirement in CLAUDE.md Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * Show batch_size field only when enable_batching is true Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * update batch size for subscribe and unsubscribe profile actions --------- Co-authored-by: Claude Opus 4.6 <[email protected]>
1 parent 83cfc2c commit 42598d2

12 files changed

Lines changed: 121 additions & 16 deletions

File tree

CLAUDE.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ yarn browser jest --testPathPattern="braze"
5858
yarn core jest --testPathPattern="mapping-kit"
5959
```
6060

61+
> **Note:** Always run tests with `TZ=UTC` (e.g. `TZ=UTC yarn cloud test`) to ensure snapshot tests produce consistent results regardless of local timezone.
62+
6163
### Lint & Type Checking
6264

6365
```bash
@@ -179,10 +181,62 @@ To override automatic HTTP error handling, set `throwHttpErrors: false` on the r
179181

180182
### Batching
181183

184+
**Important**: Batching is handled by a component within Segment BEFORE your `performBatch` method is called. You do not need to implement chunking logic in your destination code.
185+
182186
- Implement `performBatch` for high-volume destinations
183187
- Use appropriate batch keys with low cardinality to avoid inefficient batching
184188
- Test various batch sizes and edge cases
185189

190+
#### batch_size vs batch_bytes
191+
192+
Both fields control how Segment's platform groups events before calling your `performBatch` method:
193+
194+
**batch_size** (recommended for customer exposure with caution):
195+
196+
- Controls the maximum **number of events** in a batch
197+
- Default: 1000 events (subject to change)
198+
- Use when: Destination API has limits on number of records per request
199+
- Customer exposure: Use judgement - expose only when necessary (e.g., RETL sources with large records)
200+
- Always enforce min/max validation when exposed (e.g., `minimum: 100, maximum: 10000`)
201+
202+
**batch_bytes** (generally should NOT be exposed):
203+
204+
- Controls the maximum **payload size in bytes** of a batch
205+
- Default: 4MB (subject to change)
206+
- Use when: Destination API has strict request body size limits
207+
- Customer exposure: Avoid exposing to customers - can significantly impact delivery performance
208+
- Keep `unsafe_hidden: true` by default
209+
210+
**Example field definitions**:
211+
212+
```typescript
213+
fields: {
214+
batch_size: {
215+
label: 'Batch Size',
216+
description: 'Maximum number of events to include in each batch.',
217+
type: 'number',
218+
unsafe_hidden: false, // Only expose if customers need control
219+
default: 10000,
220+
minimum: 100,
221+
maximum: 10000,
222+
required: false
223+
},
224+
batch_bytes: {
225+
label: 'Batch Bytes',
226+
description: 'Maximum size of a batch in bytes.',
227+
type: 'number',
228+
unsafe_hidden: true, // Avoid exposing to customers
229+
default: 2000000, // 2MB
230+
required: false
231+
}
232+
}
233+
```
234+
235+
**Batching behavior**:
236+
237+
- Batch sizes are not guaranteed - may be smaller than configured limit
238+
- Lower event volumes = smaller actual batch sizes
239+
186240
### Security
187241

188242
- Never expose or log sensitive information like auth tokens or PII

packages/destination-actions/src/destinations/klaviyo/addProfileToList/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const action: ActionDefinition<Settings, Payload> = {
2929
list_id: { ...list_id },
3030
external_id: { ...external_id },
3131
enable_batching: { ...enable_batching },
32-
batch_size: { ...batch_size },
32+
batch_size: { ...batch_size, default: 10000, minimum: 100, maximum: 10000 },
3333
first_name: { ...first_name },
3434
last_name: { ...last_name },
3535
image: { ...image },

packages/destination-actions/src/destinations/klaviyo/properties.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,16 @@ export const batch_size: InputField = {
4646
description: 'Maximum number of events to include in each batch. Actual batch sizes may be lower.',
4747
type: 'number',
4848
required: false,
49-
unsafe_hidden: true,
50-
default: 10000
49+
unsafe_hidden: false,
50+
depends_on: {
51+
conditions: [
52+
{
53+
fieldKey: 'enable_batching',
54+
operator: 'is',
55+
value: true
56+
}
57+
]
58+
}
5159
}
5260

5361
export const first_name: InputField = {

packages/destination-actions/src/destinations/klaviyo/removeProfile/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const action: ActionDefinition<Settings, Payload> = {
3636
required: true
3737
},
3838
enable_batching: { ...enable_batching },
39-
batch_size: { ...batch_size, default: 1000 },
39+
batch_size: { ...batch_size, default: 1000, minimum: 100, maximum: 1000 },
4040
phone_number: {
4141
label: 'Phone Number',
4242
description: `Individual's phone number in E.164 format. If SMS is not enabled and if you use Phone Number as identifier, then you have to provide one of Email or External ID.`,

packages/destination-actions/src/destinations/klaviyo/removeProfileFromList/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const action: ActionDefinition<Settings, Payload> = {
1616
phone_number: { ...phone_number },
1717
enable_batching: { ...enable_batching },
1818
country_code: { ...country_code },
19-
batch_size: { ...batch_size, default: 1000 },
19+
batch_size: { ...batch_size, default: 1000, minimum: 100, maximum: 1000 },
2020
batch_keys: {
2121
label: 'Batch Keys',
2222
description: 'The keys to use for batching the events.',

packages/destination-actions/src/destinations/klaviyo/subscribeProfile/generated-types.ts

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/destination-actions/src/destinations/klaviyo/subscribeProfile/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { PayloadValidationError } from '@segment/actions-core'
77
import { formatSubscribeProfile, formatSubscribeRequestBody } from '../functions'
88
import { SubscribeProfile } from '../types'
99
import { API_URL } from '../config'
10-
import { country_code } from '../properties'
10+
import { batch_size, country_code } from '../properties'
1111

1212
const action: ActionDefinition<Settings, Payload> = {
1313
title: 'Subscribe Profile',
@@ -82,6 +82,12 @@ const action: ActionDefinition<Settings, Payload> = {
8282
required: false,
8383
multiple: true,
8484
default: ['list_id', 'custom_source', 'historical_import']
85+
},
86+
batch_size: {
87+
...batch_size,
88+
default: 1000,
89+
minimum: 100,
90+
maximum: 1000
8591
}
8692
},
8793
dynamicFields: {

packages/destination-actions/src/destinations/klaviyo/trackEvent/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ const action: ActionDefinition<Settings, Payload> = {
9494
}
9595
},
9696
enable_batching: { ...enable_batching },
97-
batch_size: { ...batch_size, default: 1000 }
97+
batch_size: { ...batch_size, default: 1000, minimum: 100, maximum: 1000 }
9898
},
9999
perform: (request, { payload }) => {
100100
const { email, phone_number: initialPhoneNumber, external_id, anonymous_id, country_code } = payload.profile

packages/destination-actions/src/destinations/klaviyo/unsubscribeProfile/generated-types.ts

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/destination-actions/src/destinations/klaviyo/unsubscribeProfile/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { PayloadValidationError } from '@segment/actions-core'
66
import { formatUnsubscribeProfile, formatUnsubscribeRequestBody } from '../functions'
77
import { UnsubscribeProfile } from '../types'
88
import { API_URL } from '../config'
9-
import { country_code } from '../properties'
9+
import { country_code, batch_size } from '../properties'
1010

1111
const action: ActionDefinition<Settings, Payload> = {
1212
title: 'Unsubscribe Profile',
@@ -60,6 +60,12 @@ const action: ActionDefinition<Settings, Payload> = {
6060
required: false,
6161
multiple: true,
6262
default: ['list_id']
63+
},
64+
batch_size: {
65+
...batch_size,
66+
default: 100,
67+
minimum: 50,
68+
maximum: 100
6369
}
6470
},
6571
dynamicFields: {

0 commit comments

Comments
 (0)