Watch a live product demo 👀 See how Sanity powers richer commerce experiences


Reading documents back through the API.

The query API is located on:


You can also send queries to the CDN endpoint for edge-cached results:

  • projectId and dataset can be found in the Sanity Studio configuration file or in the project management dashboard
  • The <YYYY-MM-DD> is the API version you want to target. In most cases, you can use the current date to target the newest API version at the time.

While you can use the HTTP API endpoint directly, we recommend using a client library if you can.

The GET method

The basic query API endpoint is:

GET /data/query/<dataset>?query=<GROQ-query>

GROQ-queries may also use parameters. In the query, these will be prefixed by a dollar sign ($) and could look something like this: $language. These are submitted as normal URL parameters:

GET /data/query/<dataset>?query=<GROQ-query>&$language="es"

Because GROQ needs to know the type of the query param clearly, you need to enclose string values in quotation marks, while numbers and booleans are written in the normal manner:

GET /data/query/<dataset>?query=<GROQ-query>&$string="es"&$bool=true&$number=12.8

Due to limitations in some browsers, we’ve put the max limit on GET queries at 11 KB. If your URL is longer than that, you must submit the query as a POST (see below). Queries sent over POST will also be cached on the CDN.


  • querystring

    the GROQ query itself

  • explainboolean | "only"

    Whether to include the query execution plan as plain text in an explain field, which may be useful when optimizing slow queries. Valid values are true (include explain output in result), only (only return the query plan—do not execute the query), or false (do not include explain output). Note that the plan output is only advisory - the contents are not documented and subject to change without warning.

  • variablesstring

    GROQ-queries may also use parameters. In the query these will be prefixed by a dollar sign. These are submitted as normal url-params

Result (queries)

  "ms": <server-side processing time>,
  "query": <submitted query>,
  "result": <query result>

Caveat: It is common to assume that the result is always an array of documents, but it isn't. It can be any valid JSON value. If the query is *[_id=="myId"][0], the result is the document object unwrapped, for count(*[_type == 'actor' && name match 'weaver']) the result will be a number. If the query is *[_type == 'actor'].name, the result is an array of strings (given that the names are strings).

“Not found” is considered harmless

When a document is not found, GROQ still evaluates to a value. Thus, you don't get 404 errors through this endpoint. Some examples:

  • *[_id == "missing"] results in []
  • count(*[_type == "typoType"]) results in 0
  • *[_id == "missing"][0] results in null
  • *[_id == "missing"][0].someProp also results in null

Syntax errors

  "error": {
    "query": "*[",
    "description": "Expected ']' following expression",
    "start": 1,
    "end": 2,
    "type": "queryParseError"

The start/end-values correspond to character positions in the submitted query and could be used to provide visual feedback as to where the error occurred. description is a human-readable description of the error, which may be revised and improved over time and thus should not be used for machine processing while type is a machine-readable symbol that is intended to be part of the stable API.

The POST method

Queries longer than 11kB can’t be submitted using the GET method, so must be POSTed. Queries sent with the POST method will also be cached on the CDN.

POST /data/query/<dataset>

The payload is a JSON document like this:

  "query": "<the GROQ query>",
  // The params-part is optional:
  "params": {
    "language": "es" // you don't use the $-prefixes when submitting as json

The results of this endpoint are the same as its corresponding GET form described above.

Was this article helpful?