AMS Query DSL Reference


The AMS Query API uses a SQL-like Domain Specific Language (DSL) for requesting OOH measurement metrics. This document describes the query syntax and provides examples, as well as a mapping back to the structured JSON queries.

Query Structure

A query follows this general structure:

SELECT <metrics>
FROM <layer>
FOR AUDIENCE <universe> [TARGET <segment>]
WHERE <filters>
DURING <time_range>
[GROUP BY <dimensions>]
[ORDER BY <field> ASC|DESC]
[LIMIT <n>]
[VERSION <model_version_id>]

JSON Mapping

DSL ClauseJSON FieldRequired
SELECTselectYes
FROMlayerNo (default: audience)
FOR AUDIENCEaudience.universe_idYes
TARGETaudience.targetNo
WHEREfiltersYes
DURINGtimeYes
GROUP BYgroupbyNo
ORDER BYorder_byNo
LIMITlimitNo
VERSIONmodel_version_idNo

SELECT Clause

Specifies which metrics to calculate. Each metric can have an aggregation method and optional period basis.

Available Metrics

MetricDescription
impsRaw impression count (noticed exposures)
reachUnique individuals reached
reach_pctReach as percentage of universe
target_reach_pctReach as percentage of target segment
freqAverage frequency (impressions per reached person)
grpsGross Rating Points = (impressions / universe) x 100
trpsTarget Rating Points = (target impressions / target universe) x 100

Aggregation Methods

AggregationDescription
totalSum all values (default)
avgAverage across the period

Period Basis

PeriodDescription
dailyMetrics on a per-day basis
weeklyMetrics on a per-week basis
quad_weeklyMetrics on a 4-week basis (standard OOH buying period)

Syntax

SELECT total(imps), total(reach), avg(freq)
SELECT avg(imps) PER weekly

JSON

{
  "select": [
    {"metric": "imps", "agg": "total"},
    {"metric": "reach", "agg": "total"},
    {"metric": "freq", "agg": "avg"}
  ]
}

With period basis:

{
  "select": [
    {"metric": "imps", "agg": "avg", "period": "weekly"}
  ]
}

FROM Clause (Exposure Layer)

Specifies which exposure measurement layer to use. Layers represent different stages of the visibility funnel per Geopath/MRC standards.

Available Layers

LayerDescription
otsOpportunity To See - Circulation-based count of people passing the unit who have a reasonable opportunity to notice the ad
ltsLikelihood To See (VAC) - Visibility-adjusted based on unit characteristics, environment, and viewing conditions
audienceFull Audience Model - Demographic and behavioral adjustments applied (default)

Syntax

SELECT total(imps) FROM audience
SELECT total(imps) FROM lts
SELECT total(imps) FROM ots

JSON

{
  "layer": "audience"
}

FOR AUDIENCE Clause

Defines the population universe used as the denominator for GRP calculations. Optionally includes a target segment for TRP calculations.

Syntax

FOR AUDIENCE universe_id=1
FOR AUDIENCE universe_id=1 TARGET age_range=[18,49] AND sex=['M','F']

JSON

Basic universe:

{
  "audience": {
    "universe_id": 1
  }
}

With target demographic:

{
  "audience": {
    "universe_id": 1,
    "target": {
      "age_range": [18, 49],
      "sex": ["M", "F"],
      "combine": "and"
    }
  }
}

Target Segment Fields

FieldTypeDescription
age_range[min, max]Age range inclusive (e.g., [18, 34])
sex["M"], ["F"], or ["M", "F"]Biological sex filter
ethnicitystring[]Ethnicity codes per census classifications
income_range[min, max]Annual household income in USD
segment_idsstring[]Pre-defined segment IDs for custom targeting
combine"and" or "or"How to combine criteria (default: "and")

WHERE Clause (Filters)

Filters constrain which inventory and data are included in the query. Multiple filter objects in the array are combined with OR logic. Within a single filter object, fields are combined with AND logic.

Filter Types

Geographic Filters

WHERE dma_id IN (501, 803, 602)
WHERE state IN ('NY', 'CA', 'TX')
WHERE zipcode IN ('10001', '90210')
{
  "filters": [
    {
      "geo": {
        "dma_ids": [501, 803, 602],
        "states": ["NY", "CA"],
        "zipcodes": ["10001", "90210"],
        "geo_mode": "asset_location"
      }
    }
  ]
}
FieldDescription
dma_idsNielsen DMA IDs
statesUS state codes
zipcodes5-digit ZIP codes
geo_mode"asset_location" (where units are) or "audience_residence" (where viewers live)

Operator Filters

WHERE operator_id IN (1, 2, 3)
WHERE plant_id IN (100, 101)
{
  "filters": [
    {
      "operator": {
        "operator_ids": [1, 2, 3],
        "plant_ids": [100, 101]
      }
    }
  ]
}

Inventory Filters

WHERE asset_id IN ('asset_001', 'asset_002')
WHERE format IN ('billboard', 'transit')
WHERE environment IN ('roadside', 'retail')
{
  "filters": [
    {
      "inventory": {
        "asset_ids": ["asset_001", "asset_002"],
        "frame_ids": ["frame_001"],
        "format": ["billboard", "transit"],
        "environment": ["roadside", "retail"]
      }
    }
  ]
}

Campaign Filters

WHERE campaign_id IN ('camp_12345')
WHERE placement_id IN ('plc_001', 'plc_002')
{
  "filters": [
    {
      "campaign": {
        "campaign_ids": ["camp_12345"],
        "placement_ids": ["plc_001", "plc_002"]
      }
    }
  ]
}

Combining Filters

AND within a filter object:

{
  "filters": [
    {
      "geo": {"dma_ids": [501]},
      "inventory": {"format": ["billboard"]}
    }
  ]
}

This returns billboards in DMA 501.

OR across filter objects:

{
  "filters": [
    {"geo": {"dma_ids": [501]}},
    {"geo": {"dma_ids": [803]}}
  ]
}

This returns results from DMA 501 OR DMA 803.


DURING Clause (Time Range)

Specifies the date range for the query.

Syntax

DURING '2025-01-01' TO '2025-01-28'
DURING '2025-01-01' TO '2025-01-28' TIMEZONE 'America/New_York'
DURING '2025-01-01' TO '2025-01-28' AS OF '2025-02-01'

JSON

{
  "time": {
    "start_date": "2025-01-01",
    "end_date": "2025-01-28",
    "timezone": "America/New_York",
    "as_of_date": "2025-02-01"
  }
}
FieldDescription
start_dateStart date (YYYY-MM-DD, inclusive)
end_dateEnd date (YYYY-MM-DD, inclusive)
timezoneIANA timezone for time-based groupings (default: UTC)
as_of_datePoint-in-time for historical queries (audit/reproducibility)

GROUP BY Clause

Specifies dimensions to aggregate results by. Returns one row per unique combination of grouping values.

Available Dimensions

OOH Metadata

DimensionDescription
asset_idUnique identifier for an OOH asset (physical location)
frame_idUnique identifier for a frame (ad face) within an asset
operator_idMedia owner/operator identifier
operatorOperator name (for display)
formatInventory format (billboard, transit, street_furniture)
environmentPlacement environment (roadside, retail, airport)

Time

DimensionDescription
dateCalendar date (YYYY-MM-DD)
day_of_weekDay of week (0=Monday, 6=Sunday)
hourHour of day (0-23)
hour_of_weekHour index within the week (0-167)
weekISO week start date (Monday)

Geography

DimensionDescription
dmaNielsen Designated Market Area ID
stateUS state code
zipcode5-digit ZIP code

Syntax

GROUP BY operator, dma
GROUP BY week, format
GROUP BY hour

JSON

{
  "groupby": ["operator", "dma"]
}

ORDER BY Clause

Specifies sort order for results. Fields must be in select or groupby.

Syntax

ORDER BY grps DESC
ORDER BY week ASC, imps DESC

JSON

{
  "order_by": [
    {"field": "grps", "direction": "desc"}
  ]
}

LIMIT Clause

Limits the number of rows returned.

Syntax

LIMIT 20

JSON

{
  "limit": 20
}

VERSION Clause

Pins the query to a specific model version for reproducibility.

Syntax

VERSION 42

JSON

{
  "model_version_id": 42
}

Complete Examples

Example 1: Simple Impressions Query

DSL:

SELECT total(imps)
FROM audience
FOR AUDIENCE universe_id=1
WHERE dma_id IN (501)
DURING '2025-01-01' TO '2025-01-28'

JSON:

{
  "select": [{"metric": "imps", "agg": "total"}],
  "filters": [{"geo": {"dma_ids": [501]}}],
  "audience": {"universe_id": 1},
  "time": {"start_date": "2025-01-01", "end_date": "2025-01-28"},
  "layer": "audience"
}

Example 2: Reach and Frequency by Operator

DSL:

SELECT total(reach), avg(freq), total(grps)
FROM audience
FOR AUDIENCE universe_id=1
WHERE dma_id IN (501)
DURING '2025-01-01' TO '2025-01-28'
GROUP BY operator
ORDER BY grps DESC
LIMIT 20

JSON:

{
  "select": [
    {"metric": "reach", "agg": "total"},
    {"metric": "freq", "agg": "avg"},
    {"metric": "grps", "agg": "total"}
  ],
  "filters": [{"geo": {"dma_ids": [501]}}],
  "audience": {"universe_id": 1},
  "time": {"start_date": "2025-01-01", "end_date": "2025-01-28"},
  "layer": "audience",
  "groupby": ["operator"],
  "order_by": [{"field": "grps", "direction": "desc"}],
  "limit": 20
}

Example 3: Target Demographics (TRPs)

DSL:

SELECT total(imps), total(trps), total(target_reach_pct)
FROM audience
FOR AUDIENCE universe_id=1 TARGET age_range=[18,49] AND sex=['M','F']
WHERE dma_id IN (501, 803, 602)
DURING '2025-01-01' TO '2025-01-28'
GROUP BY dma

JSON:

{
  "select": [
    {"metric": "imps", "agg": "total"},
    {"metric": "trps", "agg": "total"},
    {"metric": "target_reach_pct", "agg": "total"}
  ],
  "filters": [{"geo": {"dma_ids": [501, 803, 602]}}],
  "audience": {
    "universe_id": 1,
    "target": {
      "age_range": [18, 49],
      "sex": ["M", "F"],
      "combine": "and"
    }
  },
  "time": {"start_date": "2025-01-01", "end_date": "2025-01-28"},
  "layer": "audience",
  "groupby": ["dma"]
}

Example 4: Weekly Campaign Performance

DSL:

SELECT total(imps)
FROM audience
FOR AUDIENCE universe_id=1
WHERE campaign_id IN ('camp_12345')
DURING '2025-01-01' TO '2025-02-28'
GROUP BY week, format
ORDER BY week ASC

JSON:

{
  "select": [{"metric": "imps", "agg": "total"}],
  "filters": [{"campaign": {"campaign_ids": ["camp_12345"]}}],
  "audience": {"universe_id": 1},
  "time": {"start_date": "2025-01-01", "end_date": "2025-02-28"},
  "layer": "audience",
  "groupby": ["week", "format"],
  "order_by": [{"field": "week", "direction": "asc"}]
}

Example 5: Hourly Daypart Analysis

DSL:

SELECT avg(imps) PER daily
FROM audience
FOR AUDIENCE universe_id=1
WHERE dma_id IN (501) AND format IN ('billboard') AND environment IN ('roadside')
DURING '2025-01-01' TO '2025-01-28' TIMEZONE 'America/New_York'
GROUP BY hour
ORDER BY hour ASC

JSON:

{
  "select": [{"metric": "imps", "agg": "avg", "period": "daily"}],
  "filters": [
    {
      "geo": {"dma_ids": [501]},
      "inventory": {"format": ["billboard"], "environment": ["roadside"]}
    }
  ],
  "audience": {"universe_id": 1},
  "time": {
    "start_date": "2025-01-01",
    "end_date": "2025-01-28",
    "timezone": "America/New_York"
  },
  "layer": "audience",
  "groupby": ["hour"],
  "order_by": [{"field": "hour", "direction": "asc"}]
}

Example 6: Pinned Version for Reproducibility

DSL:

SELECT avg(imps), avg(reach), avg(freq)
FROM lts
FOR AUDIENCE universe_id=1
WHERE asset_id IN ('asset_001', 'asset_002', 'asset_003') AND format IN ('billboard')
DURING '2025-01-01' TO '2025-06-30'
GROUP BY asset_id
VERSION 42

JSON:

{
  "select": [
    {"metric": "imps", "agg": "avg"},
    {"metric": "reach", "agg": "avg"},
    {"metric": "freq", "agg": "avg"}
  ],
  "filters": [
    {
      "inventory": {
        "asset_ids": ["asset_001", "asset_002", "asset_003"],
        "format": ["billboard"]
      }
    }
  ],
  "audience": {"universe_id": 1},
  "time": {"start_date": "2025-01-01", "end_date": "2025-06-30"},
  "layer": "lts",
  "groupby": ["asset_id"],
  "model_version_id": 42
}

Response Format

Query responses include metadata for audit trails and the result data in a columnar format.

{
  "meta": {
    "request_id": "req_abc123",
    "query_id": "qry_xyz789",
    "generated_at_utc": "2025-01-15T10:30:00Z",
    "dataset_version": "2025.01",
    "methodology_version": "1.2.0",
    "model_version_id": 42,
    "warnings": ["Data for operator_id=3 is preliminary"]
  },
  "columns": [
    {"name": "operator", "type": "string"},
    {"name": "reach", "type": "integer"},
    {"name": "freq", "type": "float"},
    {"name": "grps", "type": "float"}
  ],
  "rows": [
    ["Lamar Advertising", 2345678, 4.2, 125.6],
    ["Clear Channel Outdoor", 1987654, 3.8, 98.4],
    ["Outfront Media", 1654321, 3.5, 76.2]
  ],
  "next_page_token": null
}

Pagination

For large result sets, use the next_page_token to fetch subsequent pages:

{
  "page_token": "eyJvZmZzZXQiOjEwMH0="
}

What’s Next