Tealium EventStream
If you already have a CDP, Signal can be its first-party collector. This integration forwards events from Signal into your existing Tealium EventStream so EventStream’s connector fan-out continues unchanged, while Signal replaces utag.js with a first-party server-side collector on your own domain.
Signal is not a replacement for Tealium. EventStream remains your downstream activation and connector layer; Signal sits in front of it as the upstream first-party collector. Use this integration if you already run Tealium and want first-party collection without disturbing existing connectors.
Prerequisites
- A Tealium account with EventStream provisioned.
- Your Tealium account and profile names.
- An HTTP API data source configured in EventStream, and its data source key.
Get your credentials
Locate your account and profile names
In the Tealium dashboard, your account and profile appear in the top navigation (e.g. account acme, profile main). Note both values exactly — they’re case-sensitive.
Create an HTTP API data source
In EventStream, open Sources > Data Sources and click Add Data Source. Choose HTTP API as the source type. Give it a name (for example “Datafly Signal”).
Copy the data source key
After saving, EventStream displays the data source key (sometimes labelled “data source ID” or “tealium_datasource”). Copy it — this is the value Signal needs.
Connect downstream connectors
Configure the EventStream connectors you want this data source to feed (e.g. Google Analytics, Meta Conversions API, audience streams). Signal-collected events will flow through each connector exactly as utag.js-collected events do.
Configure in Signal
Configuration fields
| Field | Required | Description |
|---|---|---|
tealium_account | Yes | Tealium account name. |
tealium_profile | Yes | Tealium profile name within the account. |
tealium_datasource | Yes | EventStream data source key. Stored as a secret. |
Management UI setup
- Go to Integrations > Add Integration > Tealium EventStream.
- Enter your
tealium_account,tealium_profile, andtealium_datasource. - Select the General preset.
- Choose consent categories (default:
analytics). - Save and enable.
Management API setup
curl -X POST https://api.example.com/v1/admin/integrations \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"source_id": "src_abc123",
"vendor": "tealium_eventstream",
"name": "Tealium EventStream Production",
"enabled": true,
"config": {
"tealium_account": "acme",
"tealium_profile": "main",
"tealium_datasource": "abc123"
},
"consent_categories": ["analytics"]
}'API endpoint
POST https://collect.tealiumiq.com/event
Content-Type: application/jsonAuthentication is by payload, not header: tealium_account, tealium_profile, and tealium_datasource are included in the JSON body and EventStream uses them to route the event to the correct data source.
Event mapping
Signal converts canonical event names to EventStream-friendly snake_case. Properties pass through.
| Signal event | EventStream tealium_event |
|---|---|
page | page_view |
identify | identify |
Order Completed | order_completed |
Product Viewed | product_viewed |
Checkout Started | checkout_started |
Custom events follow the same convention — snake_case the event name and it lands on tealium_event.
Example: Order Completed
Signal call:
datafly.track("Order Completed", {
order_id: "ORD-001",
total: 129.99,
currency: "USD",
products: [
{ product_id: "SKU-A", name: "Widget", price: 49.99, quantity: 2 }
]
});Payload sent to EventStream:
{
"tealium_account": "acme",
"tealium_profile": "main",
"tealium_datasource": "abc123",
"tealium_event": "order_completed",
"tealium_visitor_id": "anon_a1b2c3",
"customer_id": "user_42",
"event_id": "evt_abc123",
"event_timestamp": "2026-05-12T10:00:00.000Z",
"page_url": "https://example.com/checkout/confirmation",
"page_title": "Order confirmation",
"user_agent": "Mozilla/5.0 ...",
"ip_address": "203.0.113.50",
"order_id": "ORD-001",
"order_total": 129.99,
"order_currency": "USD",
"product_list": [
{ "product_id": "SKU-A", "name": "Widget", "price": 49.99, "quantity": 2 }
]
}Identity
| Signal field | EventStream field |
|---|---|
anonymous_id | tealium_visitor_id |
user_id | customer_id |
event_id | event_id |
context.ip | ip_address |
context.user_agent | user_agent |
context.page.url | page_url |
context.page.title | page_title |
context.page.referrer | referrer |
Signal generates a stable first-party anonymous_id and forwards it as tealium_visitor_id. When datafly.identify() is called, the same user_id arrives as customer_id on subsequent events — EventStream’s Visitor Stitching can join the two.
Consent
The default consent category for this integration is analytics. Events are only forwarded when the visitor has granted analytics consent.
Override the category list in the integration config if you need to gate delivery on a different category.
Verify
Trigger an event
Call:
datafly.track("Test Event", { source: "signal-verify" });Check Live Events in EventStream
In Tealium, open EventStream > Live Events. Filter by your data source. The event should appear within seconds. Confirm:
tealium_eventmatches the expected snake_case nametealium_visitor_idis populated- Event-specific properties are present
Confirm downstream connector delivery
Open one of your EventStream connectors and confirm the event reached it. This validates that Signal-collected events flow through each connector exactly as utag.js-collected events do.
Troubleshooting
| Problem | Solution |
|---|---|
| Events accepted (202) but missing from Live Events | tealium_account, tealium_profile, or tealium_datasource is wrong. EventStream returns 202 for malformed routing and silently drops the event. Double-check all three values exactly (they’re case-sensitive). |
| 400 from Tealium | Payload is malformed — missing required fields or wrong content type. Check the event payload in Signal’s event debugger. |
| Events appear in Live Events but not in a connector | Issue is downstream of Signal — check the connector configuration and event filter in the EventStream dashboard. |
customer_id is missing | datafly.identify() has not yet been called for the visitor. Verify identify is wired into your login / form-submit flow. |
Event names look wrong (e.g. Order Completed not order_completed) | Confirm the integration is using the General preset, which includes the snake_case event-name mapping. |
See also
- RudderStack — same pattern for RudderStack.
- Segment (as destination) — same pattern for Segment.
- Migration Playbook — phased plan to put Signal in front of an existing CDP.