Event Transformations
Event transformations modify events as they flow through SignalSmith, allowing you to rename events, add or remove properties, filter events, and enrich data without changing your source instrumentation.
Why Transformations?
Transformations solve common data engineering problems at the CDP layer:
- Standardize naming — Different sources use different naming conventions (
order_completedvsOrder CompletedvsorderCompleted) - Remove sensitive data — Strip PII before events reach certain destinations
- Enrich events — Add computed properties or external data before forwarding
- Filter noise — Drop events that are not needed downstream to reduce volume and cost
- Fix instrumentation — Correct property names or types without redeploying source code
Creating a Transformation
Via the UI
- Navigate to Events > Transformations
- Click Create Transformation
- Select the transformation type
- Configure the transformation rules
- Set the scope (which events or sources this transformation applies to)
- Set the priority (order relative to other transformations)
- Click Save
Transformation Types
Rename Event
Change the name of an event. The original event name is replaced.
| Field | Description |
|---|---|
| Source event name | The original event name to match |
| Target event name | The new event name |
Example: Rename orderCompleted to Order Completed to standardize across sources.
{
"type": "rename_event",
"source_event": "orderCompleted",
"target_event": "Order Completed"
}Add Property
Add a new property to matching events with a static value, computed value, or value derived from other properties.
| Field | Description |
|---|---|
| Property name | The property to add |
| Value source | static, copy, template, or lookup |
| Value | The value or expression |
Examples:
// Static value
{
"type": "add_property",
"property": "source_platform",
"value_source": "static",
"value": "web"
}
// Copy from another property
{
"type": "add_property",
"property": "user_email",
"value_source": "copy",
"value": "traits.email"
}
// Template with interpolation
{
"type": "add_property",
"property": "full_name",
"value_source": "template",
"value": "{{first_name}} {{last_name}}"
}Remove Property
Strip a property from matching events. Useful for removing PII or unnecessary data before forwarding.
| Field | Description |
|---|---|
| Property name | The property to remove |
{
"type": "remove_property",
"property": "ip_address"
}You can remove multiple properties by creating multiple remove transformations or by specifying an array of property names:
{
"type": "remove_property",
"properties": ["ip_address", "user_agent", "device_id"]
}Rename Property
Change a property name without modifying its value.
| Field | Description |
|---|---|
| Source property | The original property name |
| Target property | The new property name |
{
"type": "rename_property",
"source_property": "user_id",
"target_property": "userId"
}Filter Event
Drop events that match specified conditions. Filtered events are not forwarded, not written to the warehouse, and not counted toward volume limits.
| Field | Description |
|---|---|
| Action | drop (remove matching events) or keep (only keep matching events) |
| Conditions | One or more conditions to evaluate |
// Drop all events from internal users
{
"type": "filter_event",
"action": "drop",
"conditions": [
{ "property": "context.traits.email", "operator": "contains", "value": "@internal.example.com" }
]
}
// Only keep events with a userId (drop anonymous events)
{
"type": "filter_event",
"action": "keep",
"conditions": [
{ "field": "userId", "operator": "is_set" }
]
}Enrich with External Data
Add properties by looking up values from an external source. Currently supported enrichment sources:
| Source | Description |
|---|---|
| Lookup table | A key-value table uploaded to SignalSmith (e.g., country code to region mapping) |
| HTTP lookup | Call an external API to fetch enrichment data (with caching) |
// Lookup table enrichment
{
"type": "enrich",
"source": "lookup_table",
"table": "country_regions",
"lookup_key": "properties.country_code",
"output_property": "properties.region"
}
// HTTP enrichment
{
"type": "enrich",
"source": "http",
"url": "https://api.internal.example.com/users/{{userId}}/segment",
"method": "GET",
"output_property": "properties.user_segment",
"cache_ttl_seconds": 3600,
"timeout_ms": 500
}HTTP enrichments have a timeout (default 500ms) and a cache to avoid excessive API calls. If the lookup fails, the event passes through without the enrichment property.
Transformation Scope
Each transformation can be scoped to apply to specific events or sources:
| Scope | Description |
|---|---|
| All events | Applies to every event regardless of name or source |
| Specific events | Only applies to events with matching names (e.g., Order Completed, Product Viewed) |
| Specific sources | Only applies to events from specified write keys (e.g., only web events) |
| Event type | Only applies to specific event types (track, identify, page, screen, group) |
Scopes can be combined. For example, “Rename user_id to userId for track events from the mobile write key.”
Transformation Pipeline Order
When multiple transformations apply to the same event, they execute in priority order (lowest number first):
Event received
↓
Priority 1: Rename event "orderCompleted" → "Order Completed"
↓
Priority 2: Add property "source_platform" = "web"
↓
Priority 3: Remove property "ip_address"
↓
Priority 4: Enrich with region lookup
↓
Priority 5: Filter (drop internal users)
↓
Transformed event → forwarding / warehouseEach transformation receives the output of the previous one. This means:
- A rename transformation at priority 1 changes the event name, so a scope filter at priority 2 should use the new name
- A remove transformation removes a property, so subsequent transformations cannot reference it
- A filter transformation at the end drops the event after all other transformations have been applied
Reordering
To change the execution order, update the priority numbers in the transformations list. You can drag-and-drop transformations in the UI to reorder them.
Testing Transformations
Before activating a transformation, test it with sample events:
- Open the transformation configuration
- Click Test
- Paste a sample event JSON or select from recent events
- View the transformation output — the modified event is shown alongside the original for comparison
Testing does not affect live event processing.
API Reference
# List transformations
GET /api/v1/events/transformations
# Create a transformation
POST /api/v1/events/transformations
# Update a transformation
PUT /api/v1/events/transformations/{id}
# Delete a transformation
DELETE /api/v1/events/transformations/{id}
# Test a transformation
POST /api/v1/events/transformations/testBest Practices
- Order matters — Place rename and add transformations before filter transformations so filters can reference the final property names
- Test before deploying — Always test with sample events to verify the transformation produces the expected output
- Document your transformations — Use the description field to explain why each transformation exists. Future team members will thank you.
- Monitor transformation impact — Check the events dashboard to verify event volume and properties after activating a new transformation
- Prefer contracts over filters for validation — Use event contracts for schema enforcement and transformations for data modification