Snowflake

Datafly Signal writes events directly into a Snowflake table so you can analyse first-party behaviour alongside the rest of your warehouse data — no third-party tag required.

Why route Snowflake through Datafly Signal

  • The data lands in infrastructure you own. Signal writes to your Snowflake directly from your own deployment. Datafly operates no intermediary and never holds a copy of your event data.
  • Personal data is hashed on the way in. Email, phone (shaped to E.164 first), first and last name, full name and postcode are normalised (trim and lowercase) and hashed with SHA-256 inside your own deployment, so the table holds email_sha256, phone_sha256 and the other digests rather than raw personal data. A raw column is an opt-in edit to the installed blueprint.
  • 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 Retail, Insurance, Travel, Media & Streaming, Publishing, B2B / SaaS, Automotive and General. Each vertical preset names one field per property in the matching event spec, with canonical names (transaction_id, value, items), legacy aliases (order_id, revenue, products) read automatically, and numeric properties typed as numbers. Every other event still lands with its properties.
  • One consent decision governs every destination. Snowflake is gated by the same consent state as the rest of your stack, so a withdrawal applies everywhere at once.

Prerequisites

Before configuring Snowflake in Signal, you need a Snowflake account with a warehouse, database, schema, and a user with appropriate permissions.

Create a Snowflake Account

  1. Sign up at snowflake.com for a free trial or use an existing account.
  2. Choose your cloud provider (AWS, Azure, or GCP) and region.
  3. Note your Account identifier — this includes the account locator and region (e.g. xy12345.us-east-1). Find it in the Snowflake URL or under Admin > Accounts.

Create a Warehouse

  1. In the Snowflake console (Snowsight), go to Admin > Warehouses.
  2. Click + Warehouse.
  3. Enter a name (e.g. DATAFLY_WH).
  4. Set the Size (X-Small is sufficient for low to moderate event volume).
  5. Enable Auto-suspend (e.g. 5 minutes) and Auto-resume to manage costs.
  6. Click Create Warehouse.

Warehouses are billed per second while running. Auto-suspend and auto-resume ensure you only pay for compute when events are being loaded.

Create a Database and Schema

CREATE DATABASE IF NOT EXISTS ANALYTICS;
CREATE SCHEMA IF NOT EXISTS ANALYTICS.DATAFLY;

Create a Table

-- Quoted lowercase names: Signal's INSERT quotes each column, and Snowflake
-- folds unquoted names to upper case, which would not match.
CREATE TABLE ANALYTICS.DATAFLY.EVENTS (
  "message_id"      STRING,
  "event_type"      STRING,
  "event_name"      STRING,
  "anonymous_id"    STRING,
  "user_id"         STRING,
  "ip_address"      STRING,
  "user_agent"      STRING,
  "page_url"        STRING,
  "page_path"       STRING,
  "page_referrer"   STRING,
  "org_id"          STRING,
  "pipeline_id"     STRING,
  "event_timestamp" TIMESTAMP_NTZ,
  "received_at"     TIMESTAMP_NTZ,
  "properties_json" VARIANT,
  "context_json"    VARIANT
);

The VARIANT columns store the JSON natively (Signal wraps both in PARSE_JSON). Query nested fields with : notation, e.g. "properties_json":value::FLOAT.

Create a User and Role for Signal

-- Create a role for Signal
CREATE ROLE DATAFLY_SIGNAL_ROLE;
 
-- Grant warehouse usage
GRANT USAGE ON WAREHOUSE DATAFLY_WH TO ROLE DATAFLY_SIGNAL_ROLE;
 
-- Grant database and schema usage
GRANT USAGE ON DATABASE ANALYTICS TO ROLE DATAFLY_SIGNAL_ROLE;
GRANT USAGE ON SCHEMA ANALYTICS.DATAFLY TO ROLE DATAFLY_SIGNAL_ROLE;
 
-- Grant table write permission
GRANT INSERT ON TABLE ANALYTICS.DATAFLY.EVENTS TO ROLE DATAFLY_SIGNAL_ROLE;
 
-- Create user
CREATE USER DATAFLY_SIGNAL
  PASSWORD = 'your_secure_password'
  DEFAULT_ROLE = DATAFLY_SIGNAL_ROLE
  DEFAULT_WAREHOUSE = DATAFLY_WH;
 
-- Assign role to user
GRANT ROLE DATAFLY_SIGNAL_ROLE TO USER DATAFLY_SIGNAL;

Configuration

FieldTypeRequiredDescription
account_identifierstringYesYour Snowflake account identifier, including the region suffix (e.g. xy12345.us-east-1).
warehousestringYesThe Snowflake virtual warehouse to use for loading data.
databasestringYesThe Snowflake database containing the target table.
schemastringYesThe Snowflake schema containing the target table.
table_namestringYesThe target table (for example EVENTS).
usernamestringYesThe Snowflake username for authentication.
passwordsecretYesThe password for the Snowflake user account.
rolestringNoOptional Snowflake role to assume when connecting. Defaults to the user’s default role.

Signal Setup

Quick Setup

  1. Navigate to Integrations in the sidebar.
  2. Open the Integration Library tab.
  3. Find Snowflake or filter by Warehouse.
  4. Click Install, select a variant if available, and fill in the required fields.
  5. 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/snowflake/install \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Snowflake",
    "variant": "default",
    "config": {
      "account_identifier": "xy12345.us-east-1",
      "warehouse": "DATAFLY_WH",
      "database": "ANALYTICS",
      "schema": "DATAFLY",
      "table_name": "EVENTS",
      "username": "DATAFLY_SIGNAL",
      "password": "your_secure_password",
      "role": "DATAFLY_SIGNAL_ROLE"
    },
    "delivery_mode": "server_side"
  }'

Schema

Signal inserts one row per event with an INSERT ... SELECT over these columns (quoted, lower case):

ColumnSnowflake typeNotes
message_idSTRINGUnique per delivered event.
event_typeSTRINGtrack, page, identify, etc.
event_nameSTRINGSignal event name (snake_case).
anonymous_idSTRINGFirst-party visitor identifier.
user_idSTRINGLogged-in user identifier (nullable).
ip_address, user_agentSTRINGClient IP and user agent.
page_url, page_path, page_referrerSTRINGPage context.
org_id, pipeline_idSTRINGSignal identifiers.
event_timestampTIMESTAMP_NTZClient event time.
received_atTIMESTAMP_NTZTime Signal received the event.
properties_jsonVARIANTThe event as the blueprint shaped it.
context_jsonVARIANTPage, device and consent context.

Where mapped fields land

The table layout is fixed: the envelope columns above plus properties_json. The blueprint shapes properties_json: event fields from the preset (for example transaction_id, value, insurance_type, policy_term_months) sit at its top level, and the preset’s envelope block (identity digests, UTM, consent flags) sits under @root:

SELECT "event_timestamp",
       "properties_json":transaction_id::STRING AS policy_number,
       "properties_json":value::FLOAT          AS premium,
       "properties_json":"@root".email_sha256::STRING AS email_sha256
FROM ANALYTICS.DATAFLY.EVENTS
WHERE "event_name" = 'purchase';

Signal does not write mapped fields to their own typed columns yet. Create views over properties_json for the columns you query often.

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.

StoredWhat it contains
Visitor requestIP address, user agent, Accept-Language, locale and timezone
PageURL including its query string, path, title and referrer
CampaignUTM source, medium, campaign, term and content
ConsentThe visitor’s consent state
LocationGeoIP country, region and city, and the network (ASN)
DeviceScreen size; for app events the OS and version, manufacturer, model, advertising ID and IDFV when the app collected them
Vendor IDsCookie and click identifiers in vendor_ids (for example the _fbp browser ID, gclid, ttclid, the GA client ID)
Session and librarySession ID, number and engagement time; the collector’s name and version
Partner attributesProfile 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.

Snowflake is a first-party destination under your control. The default blueprint forwards all events regardless of consent category, but you can filter on the consent flags in your pipeline transforms or downstream SQL views to honour user choices: "properties_json":"@root".consent_analytics and consent_marketing from the preset, or "context_json":consent.

Testing

  1. Enable the integration in Signal and trigger a test event on your website.
  2. Open the Snowflake console and run a query:
SELECT * FROM ANALYTICS.DATAFLY.EVENTS
ORDER BY "event_timestamp" DESC
LIMIT 10;
  1. Verify that event rows are appearing with correct data.
  2. Test VARIANT querying:
SELECT "message_id", "properties_json":value::FLOAT AS value, "properties_json":currency::STRING AS currency
FROM ANALYTICS.DATAFLY.EVENTS
WHERE "event_name" = 'purchase'
ORDER BY "event_timestamp" DESC
LIMIT 5;
  1. In Signal, check the Live Events view to confirm delivery status shows as successful.

Troubleshooting

ProblemSolution
Events not appearing in SnowflakeVerify the account identifier, warehouse, database, schema, and table are correct.
Incorrect username or passwordThe username or password is incorrect. Verify the credentials. Snowflake usernames are case-insensitive but passwords are case-sensitive.
Insufficient privilegesThe role lacks the required permissions. Verify the role has USAGE on the warehouse, database, and schema, plus INSERT on the table.
Warehouse suspendedThe warehouse auto-suspended. It will auto-resume on the next query but the first request may be slower. Ensure auto-resume is enabled.
Object does not existThe database, schema, or table does not exist. Verify the names (Snowflake identifiers are case-sensitive when quoted).
Account identifier formatThe account identifier must include the region suffix. Check under Admin > Accounts in Snowsight.
Connection timeoutEnsure Signal can reach account_identifier.snowflakecomputing.com on port 443. Check network policies and firewall rules.
Warehouse credits at high volumeSignal inserts one row per event, and each insert runs on the virtual warehouse. For high-volume pipelines, land events in cloud storage and load them with Snowpipe, or use Snowpipe Streaming.

Visit Snowflake documentation for full SQL reference, VARIANT query syntax, and cost management guides.

See also