subtext_url, opens that person’s real session, and walks the decisive moments with screenshots, the component tree, network, and console. Snowplow detects; Subtext diagnoses.
This guide assumes the Subtext capture snippet is installed and capturing sessions, and a Snowplow web tracker is running — either the tag (
window.snowplow(...)) or the npm @snowplow/browser-tracker. The examples query ClickHouse — which Snowplow feeds via its Snowbridge stream forwarder or via the Lake Loader’s Iceberg/Delta output, not a dedicated loader — but any of Snowplow’s supported loader targets (Snowflake, Databricks, BigQuery, Redshift) works the same way; only the entity-column syntax differs.Attach the session URL
Snowplow attaches extra data to events as entities (custom contexts), each validated against a schema. The cleanest way to add one value to every event is a global context — define it once and the tracker sends it with every subsequent event, no per-call wiring.Define the entity schema
Entities are schema-validated, so first add a self-describing schema to your Iglu registry. A minimal one holds a single URL:Attach it as a dynamic global context
The session URL changes across sessions and carries a per-moment timestamp, so use a context generator (a function) rather than a static object. The tracker runs it for every event, reading the URL fresh, and skips the entity when there is no session yet by returningundefined. Register it once, after the tracker is initialized — every trackPageView, trackSelfDescribingEvent, and built-in event fired afterward carries the entity.
Where it lands in the warehouse
Snowplow shreds each entity into its own column or table named from the schema — for the schema above, a column likecontexts_com_yourco_subtext_session_1, an array whose first element holds { "url": "..." }. Query the URL out of that path (ClickHouse example):
atomic schema for the shredded entity name.
From signal to session
However you first hear about a problem in Snowplow — a modeled behavioral table, a Failed Events alert, a data-quality check — the path is the same: get to thesubtext_url on the affected rows, then hand it to your agent for a Detect-vs-Diagnose read. The atomic events say a user errored or dropped; the session shows what they actually experienced.
A behavioral model flags a friction point
A behavioral model flags a friction point
An analytics engineer or PM reviewing a dbt-modeled funnel built on Snowplow atomic events notices a step-completion rate falling below trend for a specific event.Query the modeled table (or Grab a few, then hand them to your agent:
atomic.events) for the affected users’ sessions and read subtext_url off the shredded entity column:A Failed Events alert
A Failed Events alert
The data engineer who owns tracking quality sees Snowplow’s Failed Events stream spike — events failing schema validation, which usually means a broken client, not just bad instrumentation.Successful events from the same users still carry the entity, so find a recent good event for an affected user and read its
subtext_url.A self-describing event looks wrong
A self-describing event looks wrong
A product analyst investigating a custom event finds a self-describing event firing at an implausible rate or with odd properties.Filter
atomic.events to that event schema and pull the session link.For agents
An autonomous agent can run the whole loop, but not against Snowplow directly. Snowplow is a pipeline, not a query product: Snowplow’s official MCP server works against the Snowplow Console — tracking plans, pipeline health, and failed-event investigation — not your event data, and querying the collector or enrichment stack is not the path. Snowplow’s value is that it lands clean, modeled events in your warehouse, so the agent story runs through the warehouse’s MCP.- If that warehouse is ClickHouse, use the official
mcp-clickhouseserver (list_databases,list_tables,run_query, read-only by default). - For Snowflake, BigQuery, or Redshift, use that warehouse’s own MCP or SQL API. The query shape is identical; only the entity-column syntax differs.
1
Discover and extract in one query
The shredded entity column returns both the friction and the link on the same rows, so a single query does discovery and extraction together:
2
Hand off to Subtext
For each URL, call
review-open(session_url=<subtext_url>) on the Subtext MCP and get a Detect-vs-Diagnose read: the model says they dropped versus what the session actually shows.The entity only round-trips if the tracker attached it at capture (see Attach the session URL); events fired before you registered the global context carry an empty array, so filter
length(...) > 0. The shredded column name is derived from your schema’s vendor, name, and version — confirm it against your atomic schema before hard-coding it. Keep the warehouse MCP read-only; a review agent never needs write access.Related
- Session Review overview — what your agent does once a session is open.
- Install the capture snippet — required before any session URL exists to attach.

