Skip to main content
Snowflake is a cloud data warehouse platform. OpenRouter can stream traces directly to your Snowflake database for custom analytics, long-term storage, and business intelligence.

Step 1: Create the traces table

Before connecting OpenRouter, create the OPENROUTER_TRACES table in your Snowflake database. You can find the exact SQL in the OpenRouter dashboard when configuring the destination:
Snowflake Table Setup

Step 2: Create access credentials

Generate a Programmatic Access Token with ACCOUNTADMIN permissions in the Snowflake UI under Settings > Authentication.
Snowflake PAT

Step 3: Enable Broadcast in OpenRouter

Go to Settings > Observability and toggle Enable Broadcast.
Enable Broadcast

Step 4: Configure Snowflake

Click the edit icon next to Snowflake and enter:
  • Account: Your Snowflake account identifier (e.g., eac52885.us-east-1). You can find your account region and your account number at the end of your Snowflake instance’s URL: https://app.snowflake.com/us-east-1/eac52885; together these make your account identifier.
  • Token: Your Programmatic Access Token.
  • Database: Target database name (default: SNOWFLAKE_LEARNING_DB).
  • Schema: Target schema name (default: PUBLIC).
  • Table: Table name (default: OPENROUTER_TRACES).
  • Warehouse: Compute warehouse name (default: COMPUTE_WH).

Step 5: Test and save

Click Test Connection to verify the setup. The configuration only saves if the test passes.

Step 6: Send a test trace

Make an API request through OpenRouter and query your Snowflake table to verify the trace was received.
Snowflake Test Trace

Example queries

Cost analysis by model

User activity analysis

Error analysis

Provider performance comparison

Usage by API key

Accessing VARIANT columns

Parsing input messages

Schema design

The dashboard-generated CREATE TABLE statement is the source of truth for setup. The field reference below describes the current schema without duplicating the generated SQL.

Field reference

Field ownership and custom metadata

OpenRouter populates all columns except for the following caller-controlled values:
  • TRACE_ID can be set with trace.trace_id. If supplied, the same trace ID can span multiple API requests.
  • PARENT_SPAN_ID can be set with trace.parent_span_id.
  • USER_ID comes from the request user field.
  • SESSION_ID comes from the request session_id field.
  • Custom values are stored in the METADATA VARIANT column.
Additional keys in trace are merged into METADATA using their original keys. Top-level request metadata.<k> values are also placed in METADATA, under the key metadata_<k>. There is no separate database column for each custom key. trace_name and generation_name affect internal trace and observation names but have no dedicated table columns. trace.span_name is accepted as a reserved request field but is currently ignored.

Observation rows and aggregation

Broadcast writes one row per observation, not one row per API request. A typical request produces:
  • One root GENERATION row with SPAN_ID equal to the generation ID. Its PARENT_SPAN_ID is NULL unless the request set trace.parent_span_id, so identify it by SPAN_TYPE = 'GENERATION', not by a null parent.
  • An optional <generation_id>:moderation SPAN row.
  • One <generation_id>:attempt-<i> SPAN row for each provider attempt.
  • An optional <generation_id>:generation SPAN row.
All rows share TRACE_ID. Child rows use the generation ID as PARENT_SPAN_ID.
Only the root GENERATION row carries the request’s tokens and cost; the other rows report zero. Filter SPAN_TYPE = 'GENERATION' for per-request counts, averages, and error rates: a failed provider attempt has STATUS = 'error' even when a fallback then served the request.
Delivery is at least once and Snowflake’s primary key is informational, so deduplicate on (TRACE_ID, SPAN_ID) for idempotent ingestion.

Typed columns

The field reference above identifies commonly queried identifiers, timestamps, model information, token metrics, and cost metrics as typed columns for efficient filtering and aggregation.

VARIANT columns

Less commonly accessed and variable-structure data is stored in the VARIANT columns identified in the field reference above. This design balances query performance with schema flexibility and storage efficiency.

Custom Metadata

Custom metadata from the trace field is stored in the METADATA VARIANT column. You can query it using Snowflake’s semi-structured data functions.

Supported Metadata Keys

Example

Querying Custom Metadata

Use Snowflake’s VARIANT column syntax to query your custom metadata:

Additional Context

  • The user field maps to the USER_ID typed column
  • The session_id field maps to the SESSION_ID typed column
  • Additional custom keys from trace are stored in the METADATA VARIANT column for flexible querying
  • trace_name and generation_name affect internal names but have no dedicated table columns
  • trace.span_name is reserved and currently ignored
  • You can create materialized views on frequently queried metadata fields for better performance

Privacy Mode

When Privacy Mode is enabled for this destination, prompt and completion content and provider error text are excluded from traces. All other trace data — token usage, costs, timing, model information, and custom metadata — is still sent normally. See Privacy Mode for details.