RudderStack
If you already have a CDP, Signal can be its first-party collector. This integration forwards events from Signal into your existing RudderStack data plane so RudderStack’s destination fan-out continues unchanged, while Signal replaces the browser SDK with a first-party server-side collector on your own domain.
Signal is not a replacement for RudderStack. RudderStack remains your downstream activation and routing layer; Signal sits in front of it as the upstream first-party collector. Use this integration if you already run RudderStack and want first-party collection without disturbing existing destinations.
Why route RudderStack through Datafly Signal
- Profiles are updated from the server, not the browser. Events reach RudderStack even when a tracker blocker or a failed page unload would have dropped a client-side call, so the profile reflects what actually happened.
- Client IP and user agent are carried in the payload. Both are taken from the original visitor request rather than your server, which is what RudderStack needs to attribute the event to the right session.
- One consent decision governs every destination. RudderStack is gated by the same consent state as the rest of your stack, so a withdrawal applies everywhere at once.
Prerequisites
- A RudderStack workspace.
- An HTTP source configured in that workspace.
- The data plane URL for your workspace.
- A source write key.
Get your credentials
Find your data plane URL
In the RudderStack dashboard, open Sources and select your HTTP source. The setup instructions panel lists the data plane URL — for example https://yourcompany.dataplane.rudderstack.com. Copy it.
Copy your write key
On the same source page, copy the Write Key. This is a secret — treat it like a password.
Confirm the source is enabled
Make sure the source is enabled in the RudderStack dashboard. If the source is paused, RudderStack will accept events at the HTTP API but they will not flow to downstream destinations.
Configure in Signal
Configuration fields
| Field | Required | Description |
|---|---|---|
data_plane_url | Yes | Your RudderStack data plane URL (e.g. https://yourcompany.dataplane.rudderstack.com). |
write_key | Yes | The HTTP source write key. Stored as a secret. |
Management UI setup
- Go to Integrations > Add Integration > RudderStack.
- Enter your
data_plane_urlandwrite_key. - 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": "rudderstack",
"name": "RudderStack Production",
"enabled": true,
"config": {
"data_plane_url": "https://yourcompany.dataplane.rudderstack.com",
"write_key": "your_write_key"
},
"consent_categories": ["analytics"]
}'API endpoint
Each call type goes to its own path of the HTTP Tracking API, authenticated with HTTP Basic (write_key:):
POST {data_plane_url}/v1/track track events
POST {data_plane_url}/v1/page page views
POST {data_plane_url}/v1/screen mobile screen views (screen_view)
POST {data_plane_url}/v1/identify identify() calls
POST {data_plane_url}/v1/group group() callsEvery call carries userId or anonymousId, messageId (the Signal event ID, which RudderStack uses for deduplication) and timestamp; page and screen carry name, group carries groupId. Calls are limited to 32 KB each.
Presets
| Preset | Key | What it sends |
|---|---|---|
| General | general | Every Signal call forwarded 1:1 to the RudderStack call of the same type, event names and properties unchanged. |
| Retail | ecommerce | As General, with Signal’s ecommerce events renamed to the Segment Ecommerce Spec V2 that RudderStack follows, so downstream destinations recognise them. |
Retail: event names
| Signal event | RudderStack event | Notes |
|---|---|---|
search | Products Searched | query from search_term |
view_item_list | Product List Viewed | list_id, category, products[] |
select_item | Product Clicked | first item’s fields flat on properties |
view_item | Product Viewed | first item’s fields flat, plus value, currency |
add_to_cart / remove_from_cart | Product Added / Product Removed | first item’s fields flat |
view_cart | Cart Viewed | products[] |
begin_checkout | Checkout Started | value, currency, coupon, products[] |
add_shipping_info / add_payment_info | Checkout Step Completed / Payment Info Entered | shipping_method / payment_method |
purchase | Order Completed | order_id, revenue, tax, shipping, coupon, affiliation, currency, products[] |
refund | Order Refunded | order_id, total, currency, products[] |
view_promotion / select_promotion | Promotion Viewed / Promotion Clicked | promotion_id, name, creative, position |
add_to_wishlist / remove_from_wishlist | Product Added to Wishlist / Product Removed from Wishlist | first item’s fields flat |
coupon_applied / coupon_denied | Coupon Applied / Coupon Denied | coupon_id |
product_shared / product_reviewed | Product Shared / Product Reviewed |
Products map item_id to product_id and sku, item_name to name, item_category to category, item_brand to brand, item_variant to variant, index to position, with price, quantity and coupon unchanged.
Example: purchase with the Retail preset
Signal call:
datafly.track("purchase", {
transaction_id: "ORD-001",
value: 129.99,
currency: "USD",
items: [
{ item_id: "SKU-A", item_name: "Widget", price: 49.99, quantity: 2 }
]
});Payload sent to {data_plane_url}/v1/track:
{
"event": "Order Completed",
"anonymousId": "anon_a1b2c3",
"userId": "user_42",
"messageId": "evt_abc123",
"timestamp": "2026-05-12T10:00:00.000Z",
"context": {
"ip": "203.0.113.50",
"userAgent": "Mozilla/5.0 ...",
"page": { "url": "https://example.com/checkout/confirmation" }
},
"properties": {
"order_id": "ORD-001",
"revenue": 129.99,
"currency": "USD",
"products": [
{ "product_id": "SKU-A", "sku": "SKU-A", "name": "Widget", "price": 49.99, "quantity": 2 }
]
}
}Identity
| Signal field | RudderStack field |
|---|---|
anonymous_id | anonymousId |
user_id | userId |
event_id | messageId |
context.ip | context.ip |
context.user_agent | context.userAgent |
context.page | context.page |
context.campaign | context.campaign |
context.library | context.library |
Signal generates a stable first-party anonymous_id and forwards it to RudderStack as anonymousId. When datafly.identify() is called, the same userId arrives at RudderStack on subsequent events.
identify() traits are sent as traits on the /identify call as the visitor supplied them, including email: RudderStack forwards identity to its own destinations and hashes per destination where a destination needs it. It is the only call that carries personal data; track and page calls carry no traits.
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 (for example advertising for marketing-focused RudderStack workspaces).
Verify
Trigger an event
Visit a page on your site with Signal and a test integration enabled, or call:
datafly.track("Test Event", { source: "signal-verify" });Check Live Events in RudderStack
In RudderStack, open Sources > your HTTP source > Live Events. The event should appear within seconds. Confirm:
eventname matches what Signal sentanonymousIdis populatedpropertiescontains the expected payload
Confirm downstream delivery
Open one of your downstream destinations connected to the source. Confirm the event reached the destination — this validates that Signal-collected events fan out exactly as RudderStack’s own SDK-collected events do.
Troubleshooting
| Problem | Solution |
|---|---|
| 401 from RudderStack | Write key is wrong, revoked, or attached to a different source. Regenerate and update the integration config. |
| 404 from RudderStack | The data_plane_url is wrong. Check the source setup panel in RudderStack and confirm the URL exactly. |
| Events accepted but not visible in Live Events | The HTTP source is paused. Re-enable it in the RudderStack dashboard. |
| Events appear in RudderStack but not in a destination | Issue is downstream of Signal — check the destination configuration and transformation in the RudderStack dashboard. |
userId is missing | datafly.identify() has not yet been called for the visitor. Verify identify is wired into your login / form-submit flow. |
See also
- Segment (as destination) — same pattern for Segment.
- Tealium EventStream — same pattern for Tealium.
- Migration Playbook — phased plan to put Signal in front of an existing CDP.