Synthetic monitors, their steps, and the locations they run from are modeled as first-class nodes in Smartscape on Grail. They share the same topology graph, semantics, and query language as the rest of your environment—hosts, services, frontends, and Kubernetes workloads. This page describes the model—its node types, their attributes, and the relationships between them—and shows how to query synthetic monitors, steps, and locations with Dynatrace Query Language (DQL).
Synthetic entities are modeled as Smartscape nodes and their relationships as edges—for details, see Smartscape on Grail. On this page, an unqualified entity or dt.entity.* refers to the Classic model.
Synthetic monitoring is modeled by the following Smartscape node types:
| Smartscape entity | Node type | Smartscape model ID | Classic entity model |
|---|---|---|---|
Browser monitor |
|
|
|
Browser monitor step |
|
|
|
HTTP monitor |
|
|
|
HTTP monitor step |
|
|
|
Network availability monitor |
|
|
|
Synthetic location |
|
|
|
The node types, their attributes, and their relationships are defined in the Smartscape - Synthetic model group in the Semantic Dictionary.
As Smartscape nodes, synthetic monitors, steps, and locations can be queried for dashboards, service level objectives (SLOs), and topology navigation. Each node type answers a different question:
| Node type | Answers questions like | Key attributes |
|---|---|---|
| Which monitors exist, who owns them, how often they run, when they last succeeded or failed, and whether they're enabled? |
|
| What individual requests or actions make up a monitor, and in what order? |
|
| Where do monitors run—which cloud, region, and city—and what can each location do? |
|
Every node also carries the common base attributes id, id_classic, name, deleted, and tags.
deleteddeleted is a soft-delete flag. A removed monitor, location, or credential isn't dropped from Smartscape immediately—its node stays queryable for a retention window with deleted == true, so recently deleted items still show up. Add | filter deleted == false to exclude them.
Tags come in two forms. The tags record holds regular tags, aggregated across all contexts; query a single context with tags:<context>. Primary tags—a curated set that Dynatrace attaches to all telemetry at ingest (for example, Kubernetes labels or cloud tags)—are carried by monitors and steps under the primary_tags.* prefix and are the fastest way to filter or group. Rule-based tags from Classic don't exist in this model.
Synthetic locations carry full geographic attributes (geo.continent.name, geo.country.name, geo.region.name, geo.city.name, geo.location.latitude, geo.location.longitude), so you can group and filter monitors by where they run and plot them on a map. Monitors expose their last successful and last failed execution times as separate attributes (last_successful_execution_timestamp, last_failed_execution_timestamp), so you can find monitors by outcome as well as by recency.
For the complete, authoritative list of attributes, types, and examples for each node type, see the Smartscape - Synthetic model group in the Semantic Dictionary.
Synthetic Smartscape entities are connected by the following relationships:
| Source | Relationship | Target | Kind | Description |
|---|---|---|---|---|
|
|
| static | Locations from which the monitor executes |
|
|
| static | Individual HTTP requests that make up the monitor |
|
|
| static | Credential vault entries the monitor reads |
|
|
| static | Credential vault entries the monitor writes back |
|
|
| dynamic | Backend service the monitor targets |
|
|
| dynamic | Frontend application the monitor is associated with |
|
|
| static | Parent monitor of the step |
|
|
| static | Locations from which the monitor executes |
|
|
| static | Steps in the browser test script |
|
|
| static | Credential vault entries the monitor reads |
|
|
| dynamic | Frontend application the monitor tests |
|
|
| static | Parent monitor of the step |
|
|
| static | Locations from which the monitor executes |
|
|
| dynamic | Host the monitor pings or connects to |
The Kind column in the table above reflects how each edge is produced. Edges come in two kinds:
monitors) or the RUM frontend a browser monitor is associated with (is_assigned_to). A monitor with no recent executions may temporarily have no dynamic edges.The contains (monitor > step) and belongs_to (step > monitor) edges describe the same link from both ends, so you can navigate from a monitor down to its steps or from a step back up to its monitor.
These edges let you see which RUM application a monitor is tied to—so you can align a monitor's results with the frontend your users actually experience. A monitor can link to a frontend in two different ways, and the distinction matters:
is_assigned_to: The frontend you explicitly assigned to the monitor, associating the monitor's results with that application.monitors: The target the monitor exercises at runtime: a Real User Monitoring (RUM) frontend for browser monitors, a backend service for HTTP monitors, or a host for network availability monitors.Both are dynamic, not static, even the assigned one: the edge is materialized from the monitor's executions rather than from its stored configuration. A link therefore appears only after the monitor has run and its target has been resolved, and it can change or disappear as executions are observed. A monitor that hasn't run recently—or whose assigned frontend or discovered target no longer resolves—may have neither edge.
The two credential edges distinguish how a monitor touches a credential vault entry:
uses: The monitor reads the credential (in a pre/post script, in the URL, or anywhere else it consumes the secret).updates: The monitor writes the credential back to the vault (for example, a script that calls the save-credential API to rotate it).This distinction lets you tell "this monitor consumes this credential" apart from "this monitor maintains this credential"—useful when planning a credential rotation. Browser monitors read credentials but never write them back, so BROWSER_MONITOR carries uses but has no updates edge—that missing row is by design, not an omission.
Use the smartscapeNodes command to query synthetic nodes. All queries run against the smartscape.nodes table.
smartscapeNodes HTTP_MONITOR| fields id, name, enabled, frequency,creation_timestamp, last_successful_execution_timestamp| sort name asc
Replace HTTP_MONITOR with BROWSER_MONITOR or NETWORK_AVAILABILITY_MONITOR for the other monitor types.
When navigating edges or working with referenced IDs, you often have a node's SmartscapeId but want its name or an attribute. The Smartscape equivalents of the classic entityName() / entityAttr() functions are getNodeName() and getNodeField(). They resolve the value directly from the ID, inline—no join or lookup needed.
smartscapeEdges is_assigned_to| filter source_type == "HTTP_MONITOR"| fields monitorName = getNodeName(source_id),frontendName = getNodeName(target_id),monitorEnabled = getNodeField(source_id, "enabled")
getNodeName(id) returns the node's name; getNodeField(id, "<attribute>") returns any attribute (for example "enabled", "cloud.provider", "geo.country.name"). The classic entityName() function is not available for Smartscape nodes.
Monitors where last_successful_execution_timestamp is more than 24 hours ago may indicate a persistent failure or a misconfigured schedule.
smartscapeNodes HTTP_MONITOR| filter enabled == true| filter isNull(last_successful_execution_timestamp)OR last_successful_execution_timestamp < now() - 24h| fields id, name, last_successful_execution_timestamp, last_failed_execution_timestamp| sort last_successful_execution_timestamp asc
last_successful_execution_timestamp reflects successful executions recorded in the Smartscape model, so a monitor with no recorded success shows null—including one that has only ever failed. For the complete historical picture, cross-reference the availability metrics; if your range may predate a monitor's Smartscape data, see Query availability during the Classic-to-Smartscape transition.
smartscapeNodes HTTP_MONITOR| filter enabled == false| fields id, name, last_modification_timestamp, last_modified_by| sort last_modification_timestamp desc
Synthetic nodes are queried with the smartscapeNodes command—there is no fetch smartscape.nodes data object. A single smartscapeNodes call accepts several node types (comma-separated) and exposes the type field, so you can list all monitor types at once without a union:
smartscapeNodes HTTP_MONITOR, BROWSER_MONITOR, NETWORK_AVAILABILITY_MONITOR| fields name, type, frequencyMinutes = frequency| sort frequencyMinutes asc
Relationships are navigated with traverse, not by expanding a field. Starting from the monitors and traversing the runs_on edge lands each row on the target SYNTHETIC_LOCATION node, whose attributes you can then group by. count() per location gives the number of monitors that run there.
smartscapeNodes HTTP_MONITOR| traverse edgeTypes: {runs_on}, targetTypes: {SYNTHETIC_LOCATION}| summarize monitorCount = count(),by: {locationId = id, locationName = name,country = geo.country.name, city = geo.city.name, cloud = cloud.provider,longitude = geo.location.longitude, latitude = geo.location.latitude}| sort monitorCount desc
The longitude and latitude fields let you plot the result directly on a map tile in a dashboard or notebook.
This query is useful before rotating or deleting a credential vault entry, to assess the blast radius of the change. The edge type itself is the role (uses = read, updates = write), and getNodeName resolves the credential and monitor names inline—no traversal or join needed. As written, it lists every monitor-to-credential relationship; uncomment the second filter and set your credential name to narrow it to one entry.
smartscapeEdges uses, updates| filter target_type == "CREDENTIAL_VAULT_ENTRY"// | filter getNodeName(target_id) == "my-credential-name"| fieldsAdd credentialName = getNodeName(target_id),monitorName = getNodeName(source_id),role = if(type == "updates", "writes", else: "reads")| fields credentialName, monitorName, monitorType = source_type, role| sort credentialName asc
The source_type field distinguishes HTTP from browser monitors. A monitor that both reads and writes the same credential appears twice—once as reads, once as writes.
Monitors link to the RUM frontend they are associated with through the is_assigned_to edge (for details, see Monitor-to-frontend relationships). Query the edges and resolve both node names inline with getNodeName—one row per monitor–frontend association:
smartscapeEdges is_assigned_to| filter source_type == "HTTP_MONITOR"| fields monitorName = getNodeName(source_id), frontendName = getNodeName(target_id)| sort monitorName asc
Use BROWSER_MONITOR for browser monitors. To get one row per monitor with an array of frontends, add | summarize frontends = collectArray(frontendName), by: {monitorName}.
Both edges are dynamic: they appear only after the monitor runs and Dynatrace resolves the target. The is_assigned_to edge links the monitor to its assigned frontend; the monitors edge links it to its runtime target (HTTP monitor > SERVICE node, browser monitor > FRONTEND node, network availability monitor > HOST node). Either edge may be absent if the monitor hasn't run recently. Before relying on them, verify what exists:
smartscapeEdges "*" | filter type == "is_assigned_to" or type == "monitors" | summarize count(), by: {type, source_type, target_type}
Steps are queryable nodes, so you can list the actions or requests that make up a monitor and sort them by their sequence. Traverse the contains edge from a monitor to its steps. To scope this to a single monitor, uncomment the filter and set your monitor ID (the ID string must be wrapped in toSmartscapeId).
smartscapeNodes BROWSER_MONITOR// | filter id == toSmartscapeId("BROWSER_MONITOR-0000000000000000")| traverse edgeTypes: {contains}, targetTypes: {BROWSER_MONITOR_STEP}| fields stepId = id, name, sequence = step.sequence_number,stepType = dt.synthetic.step.type| sort sequence asc
For HTTP monitors, use HTTP_MONITOR / HTTP_MONITOR_STEP and replace stepType with the HTTP-specific fields url = step.url and method = http.request.method.
traverse only returns steps that exist as materialized nodes. HTTP monitor step nodes (HTTP_MONITOR_STEP) are not always materialized—the contains edges can be present while the step nodes are not—so the HTTP variant may return no rows in some environments even when the monitor has steps. Browser monitor steps are materialized reliably.
Synthetic availability metrics carry the Smartscape node ID as a dimension. Each monitor type has its own metric key and dimension:
| Monitor type | Availability metric | Smartscape dimension |
|---|---|---|
HTTP |
|
|
Browser |
|
|
Network availability |
|
|
Use an execution-weighted average. A monitor's availability per time bucket and per location is based on different numbers of executions, so averaging the bucket averages (avg of avg) over- or under-weights sparse buckets. Instead, divide the summed availability by the number of data points: sum(availability) / sum(availability, rollup: count). This weights every execution equally and gives the true availability percentage.
The examples below feature the HTTP monitor type—for browser or network availability monitors, substitute dt.synthetic.http.availability with dt.synthetic.browser.availability or dt.synthetic.multi_protocol.availability respectively.
This returns one execution-weighted availability per monitor over the last 24 hours, with the monitor name and enabled state resolved inline. To scope it to a single monitor, uncomment the filter and set your ID—the dt.smartscape.* dimension is a SmartscapeId, so the literal must be wrapped in toSmartscapeId(...).
timeseries {sumAv = sum(dt.synthetic.http.availability),dataPoints = sum(dt.synthetic.http.availability, rollup: count)}, by: {monitorId = dt.smartscape.http_monitor}, from: now()-24h// | filter monitorId == toSmartscapeId("HTTP_MONITOR-0000000000000000")| fieldsAdd availability = arraySum(sumAv) / arraySum(dataPoints),name = getNodeName(monitorId),enabled = getNodeField(monitorId, "enabled")| fields monitorId, name, enabled, availability| sort availability asc
To keep the value as a per-bucket time series (for a chart) instead of a single number, replace the fieldsAdd with | fieldsAdd availability = sumAv[] / dataPoints[].
Synthetic execution metrics also carry the entities each monitor exercises in dt.synthetic.monitored_entity_ids, so you can compute availability from the perspective of a monitored application (for example, alongside its experience metrics). Group by that dimension, expand it, and filter to the application:
timeseries avgAv = avg(dt.synthetic.browser.availability),by: {dt.synthetic.monitored_entity_ids},from: now()-24h| expand dt.synthetic.monitored_entity_ids// | filter dt.synthetic.monitored_entity_ids == "APPLICATION-0000000000000000"| summarize chartData = avg(avgAv[]), by: {timeframe, interval, dt.synthetic.monitored_entity_ids}
Existing DQL queries that reference classic entity dimensions (dt.entity.http_check, dt.entity.synthetic_test, dt.entity.multiprotocol_monitor, dt.entity.synthetic_location) continue to work without modification. Synthetic telemetry is enriched with both the Smartscape node ID and the classic entity ID, so classic-entity queries remain valid and will continue to return data.
Queries against classic synthetic entities in DQL are deprecated. They remain supported for as long as Dynatrace Classic is supported, so you can adopt the new model at your own pace. New features, attributes, and relationships are added only to the Smartscape model.
This section is a temporary aid for the migration window. Skip it unless you query availability over time ranges that reach back before your environment's Smartscape migration—for recent data, the availability queries above are all you need. Once your queried ranges no longer span the migration boundary, this section can be removed without affecting the rest of the page.
During the transition, the same execution is reported under two ID families at once, so a long-range availability query has to reconcile them.
Synthetic availability metrics are emitted under two dimension families:
dt.smartscape.http_monitor, dt.smartscape.browser_monitor, dt.smartscape.network_availability_monitor): Populated for executions after the Smartscape migration.dt.entity.http_check, dt.entity.synthetic_test, dt.entity.multiprotocol_monitor): Populated for all executions, including those before the migration.During the transition period, both dimension families are populated for the same execution. A query grouped solely by dt.smartscape.http_monitor therefore misses executions from before the migration, while one grouped solely by dt.entity.http_check returns all history but uses the classic ID format. To cover a range that spans the migration, merge the two into one normalized ID with coalesce.
Every Smartscape node exposes its corresponding classic entity ID through the id_classic field. The numeric suffix is the same in both formats:
| Smartscape ID | Classic entity ID |
|---|---|
|
|
|
|
|
|
|
|
|
|
Keep these four rules in mind when writing merge queries:
coalesce in fieldsAdd, not in the timeseries by: clause. The by: clause accepts only plain dimensions; an expression there fails with MANDATORY_PARAMETER_HAS_TO_BE_FIELD_BUT_WAS_EXPRESSION. Group by both raw dimensions first, then derive the merged ID afterwards.toSmartscapeId(...), not a plain string—a raw string comparison silently returns no rows. The raw dt.smartscape.* dimension is also a SmartscapeId; the classic dt.entity.* dimension is a plain string.sum(availability) / sum(count) is unaffected, because the duplication scales the numerator and denominator equally. If you need true execution totals, deduplicate first—for details, see Synthetic calculations.contains edges exist—see List the steps of a monitor in order.Group by both the Smartscape and classic dimensions, merge them into a single monitorId with coalesce, and compute the execution-weighted average so the result is correct even where both dimension families overlap. The toSmartscapeId and replaceString functions convert a classic entity ID to its Smartscape equivalent. As written, it covers every HTTP monitor over 90 days; uncomment the filter and set your ID to scope it to one.
timeseries {sumAv = sum(dt.synthetic.http.availability),dataPoints = sum(dt.synthetic.http.availability, rollup: count)}, by: {dt.smartscape.http_monitor, dt.entity.http_check}, from: now()-90d| fieldsAdd monitorId = coalesce(dt.smartscape.http_monitor,toSmartscapeId(replaceString(toString(dt.entity.http_check), "HTTP_CHECK", "HTTP_MONITOR")))// | filter monitorId == toSmartscapeId("HTTP_MONITOR-0000000000000000")| summarize sumAv = sum(sumAv[]), dataPoints = sum(dataPoints[]), by: {timeframe, interval, monitorId}| fieldsAdd av = sumAv[] / dataPoints[], avg = arraySum(sumAv) / arraySum(dataPoints)| fieldsRemove sumAv, dataPoints
For browser and network availability monitors, substitute the metric key and Smartscape dimension from the availability metric reference, together with the classic dimension and the replaceString prefix pair from The dual-ID model. For example, browser monitors use sum(dt.synthetic.browser.availability), group by {dt.smartscape.browser_monitor, dt.entity.synthetic_test}, and replaceString(toString(dt.entity.synthetic_test), "SYNTHETIC_TEST", "BROWSER_MONITOR").
This computes one execution-weighted 30-day availability per HTTP monitor and handles both Smartscape and classic data in one query. getNodeName / getNodeField add the monitor name and enabled state from the merged monitorId inline.
timeseries {sumAv = sum(dt.synthetic.http.availability),dataPoints = sum(dt.synthetic.http.availability, rollup: count)}, by: {dt.smartscape.http_monitor, dt.entity.http_check}, from: now()-30d| fieldsAdd monitorId = coalesce(dt.smartscape.http_monitor,toSmartscapeId(replaceString(toString(dt.entity.http_check), "HTTP_CHECK", "HTTP_MONITOR")))| summarize sumAv = sum(sumAv[]), dataPoints = sum(dataPoints[]), by: {monitorId}| fieldsAdd availability = arraySum(sumAv) / arraySum(dataPoints),name = getNodeName(monitorId), enabled = getNodeField(monitorId, "enabled")| sort availability asc| fields name, enabled, availability, monitorId
Monitors that ran only before the migration and no longer exist as Smartscape nodes still appear (their availability is counted), but getNodeName returns null for them—there is no current node to resolve.
As written, this lists the classic ID for every monitor. To look up one monitor, uncomment the filter and set its Smartscape ID:
smartscapeNodes HTTP_MONITOR// | filter id == toSmartscapeId("HTTP_MONITOR-0000000000000000")| fields id, classicId = id_classic
The id field is a SmartscapeId, so the filter literal must be wrapped in toSmartscapeId(...). The id_classic field, by contrast, is a plain string and is filtered directly (see the next query).
As written, this lists the Smartscape ID for every monitor. To look up one, uncomment the filter and set its classic entity ID (a plain string—no toSmartscapeId needed):
smartscapeNodes HTTP_MONITOR// | filter id_classic == "HTTP_CHECK-0000000000000000"| fields id, id_classic, name