Build Your Own Integration
Datafly Signal can deliver events to any HTTP API endpoint. If Signal doesn’t have a dedicated integration for your vendor, you can build your own using the Custom Integration builder or the webhook integration.
When to Use This
- Connecting to an internal API or microservice
- Sending events to a vendor not in Signal’s integration catalog
- Custom data pipeline or ETL endpoint
- Third-party CRM, ESP, or analytics tool with an HTTP API
Two Approaches
1. Custom Webhook (Simple)
Best for: Quick setup, simple endpoints, any HTTP API
The Custom Webhook integration lets you send events to any URL with configurable authentication, headers, payload format, and batching. It supports:
- 4 authentication methods: None, Bearer Token, Basic Auth, HMAC Signature
- Custom payload templates: Transform events into any JSON structure using Handlebars
- Batching: Accumulate events and send in bulk
- Rate limiting: Control request throughput
See the Custom Webhook documentation for full details.
2. Delivery Spec (Advanced)
Best for: Complex APIs with specific authentication flows, field mapping, response parsing
A Delivery Spec is a declarative definition of how to deliver events to an HTTP API. It covers:
- Endpoint: URL with template variables, query parameters, HTTP method
- Authentication: Bearer token, Basic Auth, API key (header or query), OAuth 2.0 (client credentials, refresh token, service account)
- Payload: JSON or form-encoded body with field mappings, event wrappers, nested objects
- Headers: Static and dynamic headers (e.g. forwarding IP/User-Agent)
- Request signing: HMAC-SHA256/SHA1/SHA512 signatures
- Batching: Event accumulation with configurable max size, wait time, and byte limits
- Rate limiting: Token bucket rate limiter with configurable RPS and burst
- Response handling: Status code classification, error body parsing
Delivery Specs are managed through the admin portal. If you need a custom Delivery Spec for a vendor, contact your Datafly account manager.
Setting Up a Custom Webhook
Step 1: Identify Your Endpoint
Gather the following from your target API documentation:
- URL: The HTTP endpoint to send events to (must be HTTPS in production)
- Method: Usually POST
- Authentication: How the API authenticates requests
- Payload format: What JSON structure the API expects
- Rate limits: How many requests per second the API allows
Step 2: Choose an Authentication Method
| Method | When to Use | Config Fields |
|---|---|---|
| None | Internal endpoints, IP-allowlisted APIs | — |
| Bearer Token | Most REST APIs, API key authentication | auth_token |
| Basic Auth | Legacy APIs, some enterprise services | auth_username, auth_password |
| HMAC Signature | Webhook receivers, security-sensitive endpoints | hmac_secret, hmac_header |
Step 3: Create the Integration
- In Signal, go to Integrations > Add Integration > Custom Webhook.
- Enter your endpoint URL.
- Select the authentication method and enter credentials.
- Choose the payload format:
- Canonical: Sends the full Datafly event object as-is
- Custom Template: Transform events using Handlebars syntax
- Configure batching if your API supports bulk requests.
- Set consent categories appropriate for the data being sent.
- Click Save.
Step 4: Map Your Payload (Optional)
If your API expects a specific JSON structure, use a custom Handlebars template:
{
"config": {
"payload_format": "custom",
"payload_template": "{ \"event_type\": \"{{event}}\", \"user\": \"{{user_id}}\", \"data\": { \"page\": \"{{context.page.url}}\", \"revenue\": {{properties.total}} } }"
}
}Available template variables:
| Variable | Description |
|---|---|
{{event}} | Event name (e.g. “Order Completed”) |
{{type}} | Event type (track, page, identify) |
{{user_id}} | User ID (if identified) |
{{anonymous_id}} | Anonymous visitor ID |
{{timestamp}} | ISO 8601 timestamp |
{{context.page.url}} | Current page URL |
{{context.page.title}} | Page title |
{{context.ip}} | Visitor IP address |
{{context.user_agent}} | Browser user agent |
{{properties.*}} | Any event property |
{{traits.*}} | Any user trait |
Step 5: Test the Integration
- Enable the integration and trigger some events on your website.
- Check the Integration Detail page in Signal for delivery status.
- Verify events are arriving at your endpoint.
HMAC Verification
If you’re building a receiving endpoint, here’s how to verify HMAC signatures:
Node.js:
const crypto = require('crypto');
function verifySignature(body, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(body, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your Express handler:
app.post('/events', (req, res) => {
const sig = req.headers['x-signature-256'];
if (!verifySignature(JSON.stringify(req.body), sig, process.env.HMAC_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process event...
res.json({ ok: true });
});Python:
import hmac
import hashlib
def verify_signature(body: bytes, signature: str, secret: str) -> bool:
expected = 'sha256=' + hmac.new(
secret.encode(), body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)Go:
func verifySignature(body []byte, signature, secret string) bool {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(body)
expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(signature), []byte(expected))
}Batching Configuration
For high-volume endpoints, enable batching to reduce the number of HTTP requests:
{
"config": {
"batch_enabled": true,
"batch_size": 100,
"batch_interval_ms": 5000
}
}Events are buffered and sent as a JSON array when either:
- The buffer reaches
batch_sizeevents, or batch_interval_msmilliseconds have elapsed since the first buffered event
Troubleshooting
| Problem | Solution |
|---|---|
| 401/403 errors | Check authentication credentials. Ensure the token/password hasn’t expired. |
| 400 Bad Request | The payload format doesn’t match what the API expects. Use a custom template. |
| Timeout errors | Increase timeout_ms or check that the endpoint is reachable. |
| Events not arriving | Verify the URL is correct and the endpoint is publicly accessible (or on the same network). |
| Duplicate events | Enable event deduplication on your receiving endpoint using the event_id field. |
| Rate limit errors (429) | Reduce rate_limit_rps in the integration config to match your API’s limits. |