Azure Synapse Analytics
Datafly Signal writes events directly into a Synapse dedicated SQL pool table over the SQL Server wire protocol, so you can analyse first-party behaviour with the rest of your Azure data estate.
Why route Azure Synapse through Datafly Signal
- The data lands in infrastructure you own. Signal writes to your Azure Synapse directly from your own deployment. Datafly operates no intermediary and never holds a copy of your event data.
- Client IP and user agent are recorded as event context. Both come from the original visitor request rather than from your server, so geography and device analysis done in the warehouse reflects the actual visitor.
- Presets for eight verticals. General (the default: page, identify and the key cross-vertical events), Retail, Insurance, Travel, Media & Streaming, Publishing, B2B / SaaS and Automotive, each writing one named field per documented event property. Email, phone and names are written only as SHA-256 digests unless you deliberately change the installed blueprint.
- One consent decision governs every destination. Azure Synapse is gated by the same consent state as the rest of your stack, so a withdrawal applies everywhere at once.
Prerequisites
Before configuring Azure Synapse Analytics in Signal, you need an Azure account with a Synapse workspace, a dedicated SQL pool, and a target table.
Create an Azure Account
If you don’t already have one, sign up at azure.microsoft.com.
Create a Synapse Workspace
- In the Azure portal, search for Azure Synapse Analytics and click Create.
- Select your Subscription and Resource group.
- Enter a Workspace name (e.g.
datafly-synapse). - Select or create a Data Lake Storage Gen2 account for the workspace.
- Set the SQL administrator login and Password (for the built-in serverless SQL pool).
- Click Review + Create > Create.
Create a Dedicated SQL Pool
- Open your Synapse workspace in the Azure portal.
- Go to SQL pools > + New.
- Enter a Dedicated SQL pool name (e.g.
datafly_pool). - Choose a Performance level (start with DW100c for development, scale up for production).
- Click Review + Create > Create.
Dedicated SQL pools are billed while running. Pause the pool when not in use to save costs. Serverless SQL pools are billed per query and do not need to be paused.
Create a Table
Connect to the dedicated SQL pool using Synapse Studio, Azure Data Studio, or SSMS:
CREATE TABLE dbo.signal_events (
message_id NVARCHAR(128) NOT NULL,
event_type NVARCHAR(32) NOT NULL,
event_name NVARCHAR(256) NOT NULL,
anonymous_id NVARCHAR(256) NOT NULL,
user_id NVARCHAR(256) NULL,
ip_address NVARCHAR(64) NULL,
user_agent NVARCHAR(1024) NULL,
page_url NVARCHAR(4000) NULL,
page_path NVARCHAR(2000) NULL,
page_referrer NVARCHAR(4000) NULL,
org_id NVARCHAR(64) NULL,
pipeline_id NVARCHAR(64) NULL,
event_timestamp DATETIME2 NULL,
received_at DATETIME2 NULL,
properties_json NVARCHAR(MAX) NULL,
context_json NVARCHAR(MAX) NULL
)
WITH (
DISTRIBUTION = ROUND_ROBIN,
HEAP
);Signal inserts one row per event, so a round-robin heap is the right landing table: it takes single-row inserts without columnstore delta-store overhead. Copy into a hash-distributed columnstore table on a schedule (CTAS or INSERT ... SELECT) for analytics. The column names must match exactly; the table can have extra nullable columns.
Get the Server Endpoint
In the Synapse workspace overview, copy the Dedicated SQL endpoint (e.g. datafly-synapse.sql.azuresynapse.net). Synapse listens on TCP port 1433 and requires Encrypt=True.
Configure Firewall Rules
- In the Synapse workspace, go to Security > Firewalls.
- Add the IP addresses of your Signal deployment.
- Click Save.
Configuration
| Field | Type | Required | Description |
|---|---|---|---|
server | string | Yes | The dedicated SQL endpoint, for example datafly-synapse.sql.azuresynapse.net. |
port | string | No | Default 1433. |
database | string | Yes | The dedicated SQL pool (database) name. |
schema_name | string | No | Default dbo. |
table_name | string | Yes | The table created above. |
username | string | Yes | SQL authentication user with INSERT and SELECT on the table. |
password | secret | Yes | The user’s password. |
encrypt | string | No | true (default) requires TLS, which Synapse requires. |
Signal Setup
Quick Setup
- Navigate to Integrations in the sidebar.
- Open the Integration Library tab.
- Find Azure Synapse Analytics or filter by Warehouse.
- Click Install, select a variant if available, and fill in the required fields.
- Click Install Integration to create the integration with a ready-to-use default blueprint.
API Setup
curl -X POST http://localhost:8084/v1/admin/integration-catalog/azure_synapse/install \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Azure Synapse Analytics",
"variant": "default",
"config": {
"server": "datafly-synapse.sql.azuresynapse.net",
"port": "1433",
"database": "datafly_pool",
"schema_name": "dbo",
"table_name": "events",
"username": "sqladmin",
"password": "YOUR_PASSWORD",
"encrypt": "true"
},
"delivery_mode": "server_side"
}'What Signal writes
Each event is one row, written with a single parameterised statement that skips a message_id already in the table, so a retried delivery does not create a duplicate row:
IF NOT EXISTS (SELECT 1 FROM [dbo].[signal_events] WHERE message_id = @p1)
INSERT INTO [dbo].[signal_events] ([message_id], [event_type], [event_name], [anonymous_id], [user_id], [ip_address], [user_agent], [page_url], [page_path], [page_referrer], [org_id], [pipeline_id], [event_timestamp], [received_at], [properties_json], [context_json])
VALUES (@p1, ..., @p16)| Column | Contents |
|---|---|
message_id | Signal’s message ID (deduplication key). |
event_type, event_name | Event type (track, page, identify, …) and the Signal event name. |
anonymous_id, user_id | Visitor identifiers (user_id NULL when not set). |
ip_address, user_agent, page_url, page_path, page_referrer | From the event context. |
org_id, pipeline_id | Where the event came from. |
event_timestamp, received_at | Event time and Signal receipt time (UTC). |
properties_json | The mapped properties object as JSON text (below). |
context_json | The whole event context as JSON text, written in full (#1414). |
Only what the blueprint maps is written. The properties_json column holds the fields your installed blueprint maps and nothing else (the row contract): the global block under @root (copies of the envelope fields, UTM parameters, the analytics and marketing consent flags, and email_sha256, phone_sha256, first_name_sha256, last_name_sha256, name_sha256), and the event section’s fields at the top level (transaction_id, value, currency, items, …). Identify traits and client properties the blueprint does not map are never written. An event with no section in the blueprint still arrives, with the @root block only: add a section for any other event whose properties you need.
Query the JSON columns with JSON_VALUE, for example JSON_VALUE(properties_json, '$.transaction_id') or JSON_VALUE(properties_json, '$."@root".email_sha256').
Only a dedicated SQL pool accepts INSERT; a serverless SQL pool is read-only over the data lake (write to Azure Data Lake Storage instead). Microsoft recommends COPY for bulk loading: one insert per event, each checking the table for its message_id, suits modest volumes. At high volume, land events in Azure Data Lake Storage and load them with COPY.
The rows above were produced by Signal’s Synapse writer against SQL Server 2022 (the same T-SQL wire protocol; the WITH (DISTRIBUTION ...) clause is Synapse-only and was left out there) on 2026-09-23 (batch S1 review): three events and a retried purchase gave three rows.
Stored event context
Alongside the fields your blueprint maps (where email, phone, names and address are stored as normalised SHA-256 by default), each row carries the event’s collected context exactly as Signal received it. The blueprint does not filter or hash the context: this is deliberate (decision 2026-09-23), so the context is complete for attribution, fraud and debugging queries, and it is listed here so you can decide what to keep.
| Stored | What it contains |
|---|---|
| Visitor request | IP address, user agent, Accept-Language, locale and timezone |
| Page | URL including its query string, path, title and referrer |
| Campaign | UTM source, medium, campaign, term and content |
| Consent | The visitor’s consent state |
| Location | GeoIP country, region and city, and the network (ASN) |
| Device | Screen size; for app events the OS and version, manufacturer, model, advertising ID and IDFV when the app collected them |
| Vendor IDs | Cookie and click identifiers in vendor_ids (for example the _fbp browser ID, gclid, ttclid, the GA client ID) |
| Session and library | Session ID, number and engagement time; the collector’s name and version |
| Partner attributes | Profile attributes from partner enrichment (partner_attrs) |
They are written to the ip_address, user_agent, page_url, page_path and page_referrer columns and, in full, to the context_json column, beside anonymous_id and user_id. Click and collected IDs outside the context are stored only where the blueprint maps them.
The IP address, device and advertising IDs, and cookie and click identifiers are personal data under UK and EU GDPR. To keep any of them out of storage, strip, mask or hash the field for every integration with the organisation data layer, apply URL redaction to page URLs, or remove it in the installed blueprint; and set the storage’s retention to match your privacy notice. See Personal data by integration.
Consent
The integration’s consent category in Signal decides which events reach Azure Synapse; events that fail it are never written. Every row also carries the visitor’s consent state (context.consent / context_json, and consent_analytics / consent_marketing in @root) so downstream queries can apply their own rules.
Testing
- Enable the integration in Signal and trigger a test event on your website.
- Open Synapse Studio and navigate to the dedicated SQL pool.
- Run a query to check for events:
SELECT TOP 10 * FROM dbo.events ORDER BY timestamp DESC;- Verify that event rows are appearing with correct data.
- In Signal, check the Live Events view to confirm delivery status shows as successful.
Troubleshooting
| Problem | Solution |
|---|---|
| Serverless SQL pool | A serverless pool cannot store rows. Point Signal at a dedicated SQL pool. |
Invalid column name | The table’s columns must be the 16 in What Signal writes, with those exact names. |
| Events not appearing in the table | Verify the connection string, database, schema, and table name are correct. Ensure the dedicated SQL pool is running (not paused). |
| Connection refused / timeout | Check the Synapse firewall rules. Add Signal’s IP addresses. |
Login failed | Verify the username and password in the connection string. |
INSERT permission denied | The user needs INSERT and SELECT (the duplicate check reads the table): GRANT INSERT, SELECT ON dbo.signal_events TO your_user;. |
| SQL pool is paused | Dedicated SQL pools must be running to accept connections. Resume the pool in the Azure portal. |
Invalid object name | The table does not exist or the schema is incorrect. Verify with SELECT * FROM INFORMATION_SCHEMA.TABLES;. |
| Performance issues | Check the SQL pool performance level (DWU). Scale up if insert throughput is insufficient. |
Visit Azure Synapse Analytics documentation for full T-SQL reference, distribution strategies, and performance tuning guides.