Skip to main content

Squid vs ServiceNow TableAPI: A Detailed Comparison

This page provides an in-depth technical comparison between Squid and ServiceNow's native TableAPI, using a real-world data request as an example.

The Challenge

Let's compare how ServiceNow TableAPI and Squid solve the following data request:

Give me all relevant data on a specific laptop, including:

  • Asset information
  • Assigned user with their full details and location
  • CI location
  • Manufacturer
  • Model
  • Application Services this CI is used by
  • Network ports with name and netmask

The Score: Squid 1 — TableAPI 11

Squid satisfies this request with one HTTP request returning a complete JSON.

ServiceNow TableAPI requires eleven request/response cycles plus client-side logic to achieve the same result.

Squid vs TableAPI ComparisonThis diagram compares how Squid and ServiceNow TableAPI handle the same data request: retrieving comprehensive laptop data with all related entities including asset, assigned_to, location, manufacturer, model, used_by services, and network ports. SQUID (Left Panel - 1 Request): Squid accomplishes this with a single HTTP GET request to /api/x_a46gh_squidx/v1/data/cmdb_ci_pc_hardware_full_inline with encodedQuery and relations parameters. The response includes all data in one JSON: asset, assigned_to, location, manufacturer, model_id, used_by[], network_ports[], plus nested references like assigned_to.location and model_id.manufacturer. Advantages of Squid: - Zero client-side logic required - Recursive reference resolution - Single network round-trip - Pre-built configurations TABLEAPI (Right Panel - 11 Requests): ServiceNow TableAPI requires 11 separate requests plus client-side logic: 1. Initial Request to cmdb_ci_pc_hardware 2. Asset lookup to alm_hardware 3. Assigned To lookup to sys_user 4. User Location lookup to cmn_location 5. CI Location lookup to cmn_location 6. Manufacturer lookup to core_company 7. Model lookup to cmdb_model 8. Relations query to cmdb_rel_ci 9. Parent CI lookup to cmdb_ci 10. Service lookup to cmdb_ci_service_auto 11. Network Ports query to cmdb_ci_network_adapter Challenges with TableAPI: - Client must parse and extract links from each response - Multiple network round-trips add latency - Must know relation sys_ids in advance - Manual table targeting required BOTTOM LINE COMPARISON: - Squid: 1 request, 0 client logic operations - TableAPI: 11 requests, 10+ parse operations Score: Squid:1TableAPI:11 Retrieving comprehensive laptop data with all related entities 1SquidSingle RequestHTTP GET Request/api/.../data/cmdb_ci_pc_hardware_full_inline?encodedQuery=...&relations=used_by,network_portsComplete JSON Response✓ asset✓ assigned_to✓ location✓ manufacturer✓ model_id✓ used_by✓ network_ports✓ user_location+ Nested: assigned_to.location, model_id.manufacturerAdvantages• Zero client-side logic• Recursive reference resolution• Single network round-trip• Pre-built configurationsOne request. All data. Zero complexity.11TableAPIMultiple Requests1Initial Requestcmdb_ci_pc_hardware2Assetalm_hardware3Assigned Tosys_user4User Locationcmn_location5CI Locationcmn_location6Manufacturercore_company7Modelcmdb_model8Relationscmdb_rel_ci9Parent CIcmdb_ci10Servicecmdb_ci_service_auto11Network Portscmdb_ci_network_adapterChallenges• Parse and extract links• Multiple network round-trips• Must know relation sys_ids• Manual table targeting1Squid Requests11TableAPI Requests0Client Logic (Squid)10+Parse Ops (TableAPI)

The Request Cascade

The following diagram illustrates the cascade of requests required when using TableAPI to resolve references and relations.

TableAPI: The Request CascadeThis diagram visualizes the complexity of using ServiceNow TableAPI to retrieve comprehensive data. It shows the 11 HTTP requests required, the useless JSON responses with link/value pairs, and the arcane knowledge needed. KEY PAIN POINTS: TableAPI returns references as {"link": "...", "value": "sys_id"} with no actual data. The initial response contains 80+ fields, most empty. Each response must be parsed, links extracted, and followed with new requests. Nested references (user→location) multiply requests. Relations require knowing magic sys_ids. Generic table responses force re-querying with the correct table. TOTAL: 11 requests, 10+ parse operations, ~1.1s network time, 80+ unused fields, 100+ lines of client code.TableAPI: The Request CascadeYOUR CODESERVICENOW1GET /api/now/table/cmdb_ci_pc_hardware?sysparm_query=name=w010y7Response: 80+ fields, references are just link/value pairs"manufacturer": {"link": "https://.../core_company/aa0a6df8...", "value": "aa0a6df8..."}"assigned_to": {"link": "https://.../sys_user/c8b1c7a4...", "value": "c8b1c7a4..."}"floppy": "", "cd_speed": "", "os_service_pack": "" ... ← No data, just links!const assetUrl = ci.asset?.link; // might be null!2GET /api/now/table/alm_hardware/{sys_id}const userUrl = ci.assigned_to?.link; // check if exists3GET /api/now/table/sys_user/{sys_id}↑ User has a location reference → need ANOTHER request!const userLocUrl = user.location?.link; // NESTED! Must follow this too4GET /api/now/table/cmn_location/{sys_id}nestedconst ciLocUrl = ci.location?.link; // back to original CIconst mfgUrl = ci.manufacturer?.link; // another referenceconst modelUrl = ci.model_id?.link; // and another...5GET cmn_location/{sys_id}6GET core_company/{sys_id}7GET cmdb_model/{sys_id}⚠ RELATIONS: Requires arcane knowledge not in any responseYou must know: "Depends On::Used by" sys_id = "1a9cb166f1571100a92eb60da2bce5c5"// Where do you even find this? Trial and error? Hope someone documented it?8GET cmdb_rel_ci?child={sys_id}&type=1a9cb166f1571100a92eb60da2bce5c5"parent": {"link": "https://.../cmdb_ci/cca1591d...", ...}const parentUrl = rel.parent?.link; // extract each relation's parent// TRAP: Link points to generic cmdb_ci, not the actual table!// You'll get incomplete data. Must query twice to get real class.9GET cmdb_ci/{sys_id} → to discover actual tableconst realTable = genericCi.sys_class_name; // "cmdb_ci_service_auto"10GET cmdb_ci_service_auto/{sys_id} ← finally the right table!relations.push({ type: "Depends On", ci: serviceCi });11GET cmdb_ci_network_adapter?cmdb_ci={sys_id}const adapters = response.result.map(a => cleanAdapter(a));Finally: Manually assemble 11 responses into one coherent objectconst result = { ...ci, asset, assigned_to: { ...user, location: userLoc }, location: ciLoc, manufacturer: mfg, model: model, relations, adapters };THE COST OF TABLEAPI11requests10+parse ops~1.1snetwork time80+unused fields100+lines of code
Expand to see the sequence of all actions required with TableAPI

Retrieve initial cmdb_ci_pc_hardware JSON

  • REST Request (1): Initial request to cmdb_ci_pc_hardware table.
    • Asset: Client Logic: Extract asset link from cmdb_ci_pc_hardware json.
    • Asset: REST Request (2): Retrieve link extracted above.
    • Assigned To: Client Logic: Extract assigned_to link from cmdb_ci_pc_hardware json.
    • Assigned To: REST Request (3): Retrieve link extracted above.
      • Assigned To - Location: Client Logic: Extract location link from sys_user json.
      • Assigned To - Location: REST Request (4): Retrieve link extracted above.
    • Location: Client Logic: Extract location link from cmdb_ci_pc_hardware json (This is the location of the ci, not the user).
    • Location: REST Request (5): Retrieve link extracted above.
    • Manufacturer: Client Logic: Extract manufacturer link from cmdb_ci_pc_hardware json.
    • Manufacturer: REST Request (6): Retrieve link extracted above.
    • Model: Client Logic: Extract model_id link from cmdb_ci_pc_hardware json.
    • Model: REST Request (7): Retrieve link extracted above.

Resolving Depends On::Used by relations

  • Client Logic: Client must know that 1a9cb166f1571100a92eb60da2bce5c5 is the sys_id of Depends On::Used by cmdb_rel_type.
  • REST Request (8): Resolve Depends On::Used by relation. Returns cmdb_rel_ci JSON.
    • Parent: Client Logic: Extract parent link from cmdb_rel_ci JSON.
    • Parent: REST Request (9): Retrieve link extracted above. The target is an unspecific cmdb_ci.
    • Parent: Client Logic: Extract correct sys_class_name from returned JSON.
    • Parent: Repeat REST Request (10) with correct target table cmdb_ci_service_auto.

Resolving network ports of the example laptop

  • REST Request (11): Query cmdb_ci_network_adapter with cmdb_ci=940b0cff873379d06dc863540cbb355e.

Squid Approach

Squid uses configurations that define how entities are rendered. A single request returns all data with references recursively resolved.

The Request

https://yourinstance.service-now.com/api/x_a46gh_squidx/v1/data/cmdb_ci_pc_hardware_full_inline?encodedQuery=base_name=w010y7&relations=used_by_service,network_ports_inline
Squid GET Request StructureThis diagram illustrates the anatomy of a Squid GET request, breaking down a complete URL into its component parts and showing the three categories of query parameters available. URL ANATOMY - A Squid request consists of four main parts shown with color coding: 1. BASE PATH (gray): /api/x_a46gh_squidx/v1/data/ - The Squid API endpoint, fixed for all requests 2. CONFIGURATION (cyan): e.g., cmdb_ci_pc_hardware_full_inline - Determines database view, available fields, reference handling, and relation definitions. 3. FILTER PARAMETERS (purple): encodedQuery - Restrict which records are returned 4. RELATION PARAMETERS (red): relations - Request related data to be included QUERY PARAMETER CATEGORIES: FILTERS (restrict what data returns): - encodedQuery: ServiceNow encoded query syntax with base_ prefix for base table fields - sys_id: Retrieve specific records by sysId (comma-separated or repeated parameter) - limit: Maximum number of entities to return - updatedSince/updatedBefore: Filter by sys_updated_on timestamp (ISO8601) - filterOnTags: Filter by cmdb_key_value entries (tagName=value syntax) - filterOnTeams: Filter by cmdb_rel_team entries (team assignments) RELATIONS (request related data): - relations: Comma-separated list of relation names to resolve (e.g., used_by_service, network_ports) - {config}.relations: Request relations for specific referenced entities when using inline rendering FLAGS (toggle features): - showBlank: Include properties with null values (normally suppressed) - showTags: Include tags/key-value data (options: object or array format) - showTagsInline: Render tags directly in entity objects - showConfig: Add squid_config property showing which config rendered each entity - metaData: Include extended timing and cache statistics in response metadata - lenient: Non-strict error handling (warnings instead of errors) - development only - preservePrefix: Keep database view column prefixes (base_, lin_, etc.)/api/x_a46gh_squidx/v1/data/cmdb_ci_pc_hardware_full_inline?encodedQuery=...&relations=...ConfigurationFilter paramRelation paramFlag paramQUERY PARAMETER CATEGORIESFILTERSencodedQueryServiceNow query syntaxsys_idSpecific records by sysIdlimitMax entities to returnupdatedSince/BeforeFilter by sys_updated_onfilterOnTagsFilter by key-value entriesfilterOnTeamsFilter by team assignmentsRestrict dataRELATIONSrelationsComma-separated list ofrelation names to resolve{config}.relationsRequest relations forspecific referenced entitiesSupported Types:• CMDB relations• 1-to-N relations• M-to-N via junction tablesAdd related dataFLAGSshowBlankInclude null valuesshowTagsInclude key-value datashowTagsInlineTags in entity objectsshowConfigShow rendering configmetaDataExtended timing infolenientWarnings vs errorspreservePrefixKeep column prefixesUsage:Flags are boolean - just includethe parameter name:?showTags&metaDataToggle features

Request Components

cmdb_ci_pc_hardware_full_inline

The requested configuration.

By convention, most predefined configurations align with ServiceNow tables. full_inline indicates we want all data inlined rather than referenced.

encodedQuery

Restricts the result set using any valid ServiceNow encodedQuery (with some restrictions).

relations

Specifies which relations to resolve:

  • used_by_service — adds any cmdb_ci_service referencing this CI via Depends On::Used by
  • network_ports_inline — adds any cmdb_ci_network_adapter referencing this CI

Example Response Excerpts

Recursively resolved reference (assigned_to):

{
"assigned_to": {
"active": true,
"email": "rainer@arc46.io",
"first_name": "Rainer",
"location": {
"city": "Bern",
"country": "Switzerland",
"full_name": "CH/Bern/Läuferplatz 11",
"name": "Läuferplatz 11",
"sys_id": "483aad38872482903efcec230cbb357f"
},
"sys_class_name": "sys_user",
"sys_id": "c8b1c7a4874561103efcec230cbb354d",
"user_name": "rainer"
}
}

Notice that location within sys_user is recursively resolved.

Resolved relation (used_by):

{
"used_by": [
{
"name": "service.mobile_workplace_performance",
"service_classification": "Application Service",
"sys_class_name": "cmdb_ci_service_auto",
"sys_id": "cca1591d8778ce106dc863540cbb35a6"
}
]
}

Resolved relation (network_ports):

{
"network_ports": [
{
"name": "eth0",
"netmask": "255.255.255.0",
"sys_class_name": "cmdb_ci_network_adapter",
"sys_id": "2b94d97b877fb1146dc863540cbb350e"
},
{
"name": "wlan0",
"netmask": "255.255.255.0",
"sys_class_name": "cmdb_ci_network_adapter",
"sys_id": "8744113f877379503efcec230cbb356b"
}
]
}
Expand to see the full JSON returned by Squid
{
"metadata": {
"git": "squid-0.0.3+8-bf5cb0c",
"build": "2024-03-10T13:00:39.981Z",
"licensed_max_entities": "Unlimited",
"config": "cmdb_ci_pc_hardware_full_inline",
"request_received": "2024-03-10T13:14:33.463Z",
"parse_config": "184ms",
"query_start": "2024-03-10T13:14:33.747Z",
"query_duration": "2ms",
"query_returned": "2024-03-10T13:14:33.749Z",
"row_count": 1,
"limit": 1,
"sysIds": [
"940b0cff873379d06dc863540cbb355e"
],
"combined_filter": "base_sys_idIN940b0cff873379d06dc863540cbb355e"
},
"data": [
{
"asset": {
"display_name": "23282981 - Lenovo ThinkPad P16 Gen1",
"sys_class_name": "alm_hardware",
"sys_id": "d210687387b7f9d06dc863540cbb3506",
"sys_updated_on": "2024-02-22T12:24:46Z"
},
"asset_tag": "23282981",
"assigned_to": {
"active": true,
"email": "rainer@arc46.io",
"first_name": "Rainer",
"location": {
"city": "Bern",
"cmn_location_type": "site",
"country": "Switzerland",
"full_name": "CH/Bern/Läuferplatz 11",
"name": "Läuferplatz 11",
"street": "Läuferplatz 11",
"sys_id": "483aad38872482903efcec230cbb357f",
"sys_updated_on": "2024-02-21T16:38:28Z",
"zip": "3011"
},
"sys_class_name": "sys_user",
"sys_id": "c8b1c7a4874561103efcec230cbb354d",
"user_name": "rainer"
},
"attestation_status": "Not Yet Reviewed",
"attested": false,
"can_print": false,
"category": "Hardware",
"cd_rom": false,
"cost_cc": "USD",
"fault_count": 0,
"form_factor": "Laptop",
"hardware_status": "installed",
"hardware_substatus": "in_use",
"install_status": 1,
"internet_facing": true,
"life_cycle_stage": "Operational",
"life_cycle_stage_status": "In Use",
"location": {
"city": "Bern",
"cmn_location_type": "site",
"country": "Switzerland",
"full_name": "CH/Bern/Läuferplatz 11",
"name": "Läuferplatz 11",
"street": "Läuferplatz 11",
"sys_id": "483aad38872482903efcec230cbb357f",
"sys_updated_on": "2024-02-21T16:38:28Z",
"zip": "3011"
},
"manufacturer": {
"city": "Morrisville",
"country": "USA",
"name": "Lenovo",
"sys_class_name": "core_company",
"sys_id": "aa0a6df8c611227601cd2ed45989e0ac"
},
"model_id": {
"asset_tracking_strategy": "leave_to_category",
"asset_tracking_unit": {
"sys_id": "51a74add0f233300fee7579ac4767e59",
"sys_class_name": "cmdb_model_unit"
},
"bundle": false,
"certified": false,
"cmdb_model_category": [
"4fbbb127876f3d106dc863540cbb3519"
],
"comments": "Mietmodell",
"cost": "0",
"customer_visible": false,
"display_name": "Lenovo ThinkPad P16 Gen1",
"energy_star": false,
"life_cycle_stage": "To Be Determined",
"life_cycle_stage_status": "To Be Determined",
"manufacturer": {
"city": "Morrisville",
"country": "USA",
"name": "Lenovo",
"sys_class_name": "core_company",
"sys_id": "aa0a6df8c611227601cd2ed45989e0ac"
},
"name": "ThinkPad P16 Gen1",
"picture": "d4866ada87b04a503efcec230cbb35c4",
"rack_units": 1,
"salvage_value": "0",
"status": "In Production",
"sys_class_name": "cmdb_hardware_product_model",
"sys_created_by": "import.systemx",
"sys_created_on": "2023-02-14T14:17:19Z",
"sys_id": "70a44cbf87f739d06dc863540cbb3524",
"sys_mod_count": 72,
"sys_updated_by": "system",
"sys_updated_on": "2024-03-09T23:09:38Z",
"type": "Generic",
"unit_of_measure_system": "us imperial"
},
"monitor": false,
"name": "w010y7",
"operational_status": 1,
"serial_number": "PF3TE9JZ",
"skip_sync": false,
"subcategory": "Computer",
"sys_class_name": "cmdb_ci_pc_hardware",
"sys_created_by": "system",
"sys_created_on": "2023-06-09T16:44:08Z",
"sys_id": "940b0cff873379d06dc863540cbb355e",
"sys_mod_count": 45,
"sys_updated_by": "system",
"sys_updated_on": "2024-03-09T23:27:48Z",
"unverified": false,
"virtual": false,
"used_by": [
{
"name": "service.mobile_workplace_performance",
"service_classification": "Application Service",
"sys_class_name": "cmdb_ci_service_auto",
"sys_id": "cca1591d8778ce106dc863540cbb35a6"
}
],
"network_ports": [
{
"name": "eth0",
"netmask": "255.255.255.0",
"sys_class_name": "cmdb_ci_network_adapter",
"sys_id": "2b94d97b877fb1146dc863540cbb350e"
},
{
"name": "wlan0",
"netmask": "255.255.255.0",
"sys_class_name": "cmdb_ci_network_adapter",
"sys_id": "8744113f877379503efcec230cbb356b"
}
]
}
],
"relations": {},
"referenced": {}
}

TableAPI Approach

The ServiceNow TableAPI will eventually give you all the data Squid provides — it just requires significantly more work.

The Request

https://yourinstance.servicenow.com/api/now/table/cmdb_ci_pc_hardware?sysparm_query=name%3Dw010y7

Limitations

No Reference Resolution

TableAPI renders references as links, not data:

{
"manufacturer": {
"link": "https://yourinstance.servicenow.com/api/now/table/core_company/aa0a6df8c611227601cd2ed45989e0ac",
"value": "aa0a6df8c611227601cd2ed45989e0ac"
}
}

Every reference requires an additional HTTP request to resolve.

Display Value Option

Using sysparm_display_value=true provides display values:

{
"manufacturer": {
"display_value": "Lenovo",
"link": "https://yourinstance.servicenow.com/api/now/table/core_company/aa0a6df8c611227601cd2ed45989e0ac"
}
}

But display values are UI-dependent and ambiguous — not suitable for reliable integrations.

Verbose Output with sysparm_display_value=all

{
"os_service_pack": {
"display_value": "",
"value": ""
},
"cpu_core_thread": {
"display_value": "",
"value": ""
},
"cpu_manufacturer": {
"display_value": "",
"value": ""
}
}

Highly verbose without additional value.

No Native Relation Resolution

To find services associated with the laptop, you must query cmdb_rel_ci explicitly:

https://yourinstance.servicenow.com/api/now/table/cmdb_rel_ci?sysparm_query=child%3D940b0cff873379d06dc863540cbb355e%5Etype%3D1a9cb166f1571100a92eb60da2bce5c5

This returns relation records, not the actual service data — requiring yet another request.

Expand to see the full JSON returned by TableAPI
{
"result": [
{
"os_address_width": "",
"attested_date": "",
"operational_status": "1",
"os_service_pack": "",
"cpu_core_thread": "",
"cpu_manufacturer": "",
"sys_updated_on": "2024-03-09 23:27:48",
"discovery_source": "",
"first_discovered": "",
"due_in": "",
"gl_account": "",
"invoice_number": "",
"sys_created_by": "system",
"ram": "",
"warranty_expiration": "",
"cpu_name": "",
"cpu_speed": "",
"owned_by": "",
"checked_out": "",
"disk_space": "",
"sys_domain_path": "/",
"business_unit": "",
"object_id": "",
"maintenance_schedule": "",
"cost_center": "",
"attested_by": "",
"dns_domain": "",
"assigned": "",
"life_cycle_stage": {
"link": "https://yourinstance.servicenow.com/api/now/table/life_cycle_stage?name=Operational",
"value": "Operational"
},
"purchase_date": "",
"cd_speed": "",
"short_description": "",
"floppy": "",
"managed_by": "",
"os_domain": "",
"can_print": "false",
"last_discovered": "",
"sys_class_name": "cmdb_ci_pc_hardware",
"cpu_count": "",
"manufacturer": {
"link": "https://yourinstance.servicenow.com/api/now/table/core_company/aa0a6df8c611227601cd2ed45989e0ac",
"value": "aa0a6df8c611227601cd2ed45989e0ac"
},
"life_cycle_stage_status": {
"link": "https://yourinstance.servicenow.com/api/now/table/life_cycle_stage_status?name=In+Use",
"value": "In Use"
},
"vendor": "",
"model_number": "",
"assigned_to": {
"link": "https://yourinstance.servicenow.com/api/now/table/sys_user/c8b1c7a4874561103efcec230cbb354d",
"value": "c8b1c7a4874561103efcec230cbb354d"
},
"start_date": "",
"os_version": "",
"serial_number": "PF3TE9JZ",
"cd_rom": "false",
"support_group": "",
"correlation_id": "",
"unverified": "false",
"attributes": "",
"asset": {
"link": "https://yourinstance.servicenow.com/api/now/table/alm_asset/d210687387b7f9d06dc863540cbb3506",
"value": "d210687387b7f9d06dc863540cbb3506"
},
"cpu_core_count": "",
"form_factor": "Laptop",
"skip_sync": "false",
"most_frequent_user": "",
"attestation_score": "",
"sys_updated_by": "system",
"sys_created_on": "2023-06-09 16:44:08",
"cpu_type": "",
"sys_domain": {
"link": "https://yourinstance.servicenow.com/api/now/table/sys_user_group/global",
"value": "global"
},
"install_date": "",
"asset_tag": "23282981",
"hardware_substatus": "in_use",
"fqdn": "",
"change_control": "",
"internet_facing": "true",
"delivery_date": "",
"hardware_status": "installed",
"install_status": "1",
"supported_by": "",
"u_compliance_relevant": "",
"name": "w010y7",
"subcategory": "Computer",
"default_gateway": "",
"chassis_type": "",
"virtual": "false",
"assignment_group": "",
"managed_by_group": "",
"sys_id": "940b0cff873379d06dc863540cbb355e",
"po_number": "",
"checked_in": "",
"sys_class_path": "/!!/!2/!(/!6",
"mac_address": "",
"company": "",
"justification": "",
"department": "",
"comments": "",
"cost": "",
"os": "",
"attestation_status": "Not Yet Reviewed",
"cmdb_ot_entity": "",
"sys_mod_count": "45",
"monitor": "false",
"ip_address": "",
"model_id": {
"link": "https://yourinstance.servicenow.com/api/now/table/cmdb_model/70a44cbf87f739d06dc863540cbb3524",
"value": "70a44cbf87f739d06dc863540cbb3524"
},
"duplicate_of": "",
"sys_tags": "",
"cost_cc": "USD",
"order_date": "",
"schedule": "",
"environment": "",
"due": "",
"attested": "false",
"location": {
"link": "https://yourinstance.servicenow.com/api/now/table/cmn_location/870a2138872482903efcec230cbb3558",
"value": "870a2138872482903efcec230cbb3558"
},
"category": "Hardware",
"fault_count": "0",
"lease_id": ""
}
]
}

Summary

AspectSquidTableAPI
HTTP requests for example111
ReferencesRecursively resolvedLinks only
RelationsIncluded on requestSeparate queries required
Client logic requiredNoneExtensive
Output controlConfiguration-drivenLimited parameters
Do more with less

Squid delivers complete, structured data in a single request — no client-side assembly required.

We track. Ok?