Querying for image URLs in a content array in Sanity

16 replies
Last updated: Jan 15, 2023
Howdy. This might be a dumb question but what's the best way to get the url of an image that is returned inside a content array? Right now all I can see from the return is this:

2: Object { _key: "00af18309329", _type: "image", asset: {…} }

_key: "00af18309329"

_type: "image"

asset: Object { _ref: "image-efd90ba5e6942927a7bb04b72e8b7bb74494dd63-4896x3264-jpg", _type: "reference" }

_ref: "image-efd90ba5e6942927a7bb04b72e8b7bb74494dd63-4896x3264-jpg"

_type: "reference"

<prototype>: Object { … }

<prototype>: Object { … }
How would I add the Image Url to this return?

Here are my queries:



const entryFields = groq`
  _id,
  title,
  date,
  excerpt,
  content,
  topics,
  "slug": slug.current,
`

export const indexQuery = groq`
*[_type == "entry"] | order(date desc, _updatedAt desc) {
  ${entryFields}
}`
Thanks!
AI Update

You need to "dereference" the asset reference in your GROQ query to get the full image URL. Right now you're just getting the reference object, not the actual asset data.

Here's how to fix your query:

*[_type == "entry"] | order(date desc, _updatedAt desc) {
  _id,
  title,
  date,
  excerpt,
  content[] {
    ...,
    _type == "image" => {
      ...,
      asset->
    }
  },
  topics,
  "slug": slug.current,
}

The key part is asset-> - the -> operator follows the reference and expands it to include the full asset document, which contains the url field.

Alternatively, you can be more explicit and just grab the URL directly:

*[_type == "entry"] | order(date desc, _updatedAt desc) {
  _id,
  title,
  date,
  excerpt,
  content[] {
    ...,
    _type == "image" => {
      ...,
      "url": asset->url
    }
  },
  topics,
  "slug": slug.current,
}

This will add a url field to your image objects in the content array that contains the full CDN URL like https://cdn.sanity.io/images/....

If you want to use Sanity's image transformation features (recommended for optimized delivery), you can use the @sanity/image-url package on the frontend. But getting the URL directly like this works too if you just need the base image URL.

Hey
user B
! You can dereference an image's asset to get all of its data. You can read about dereferencing here . Given that the object you shared has a key, I'm assuming it's inside of an array, so querying it would look like this:
<name-of-image-array>[]{
  'imageUrl': asset->url
}
Thank you so much! I will give this a go. Appreciate it.
How could I adjust this to work with an array of different types? Where I only need to query for the image url if the type is an image.
This is the array:

{name: 'content', 
title: 'Content', 
type: 'array', 
of: [{ type: 'block'}, 
{type: 'image'}, 
{type: 'mux.video'}, 
{type: link.name}
              ]},
You can set up a conditional one of the methods here . That way you can control what your query does depending on the type.
TYSM. Would you mind checking the code below for my query and telling me where I'm messing up? I am trying to return all of the content array with the image type dereferenced to include the image url. Content is an array of mixed types.

*[_type == "entry"] | order(date desc, _updatedAt desc) {
  _id,
  title,
  date,
  excerpt,
  content[]{
    _type == "image" => { 
      @-> {url}
    }
  },
  topics,
  "slug": slug.current,
}
And this is the error:
ClientError: Attribute or a string key expected
Ah, so if you're getting a field from a reference you need to give it a name. Something like this should work:
*[_type == "entry"] | order(date desc, _updatedAt desc) {
  _id,
  title,
  date,
  excerpt,
  content[]{
    _type == "image" => { 
      'url': @->url
    }
  },
  topics,
  "slug": slug.current,
}
Thx! Yeah that works partially, the issue is that it only will return data for the items in the array with type image. How do I get all the data for the other types? Thanks!
You can use the spread operator to add in all those other fields:
*[_type == "entry"] | order(date desc, _updatedAt desc) {
  _id,
  title,
  date,
  excerpt,
  content[]{
    ..., //this means add all fields
    _type == "image" => { 
      'url': @->url
    }
  },
  topics,
  "slug": slug.current,
}
OHHHH I'm so dumb. I totally thought "...," just meant 'put whatever here'
Thank you!'
Haha, I feel like that's a totally understandable interpretation.
Thanks again! Got that all working but ran into another roadblock. I created a type called "doubleImage" which is an object with two image fields ( 'leftImage' and 'rightImage'). I'm trying to get the url from each image but can't seem to get the syntax right... As you see below my thinking was to add a condition for the type 'doubleImage' followed by one for 'image' to get the url for each image in the object, but something is not right.

*[_type == "entry"] | order(date desc, _updatedAt desc) {
  _id,
  title,
  date,
  excerpt,
  content[]{
    ...,
    _type == "image" => { 
      'url': asset->url,
      ...,
    },
    _type == "doubleImage" => { 
      _type == "image" => { 
        'url': asset->url,
        ...,
      },
      ...,
    },
  },
  topics,
  "slug": slug.current,
}
The portion of the return with the array in question:

content: Array(7) [ {…}, {…}, {…}, … ]

0: Object { _key: "93bf8b952054", _type: "block", style: "normal", … }

1: Object { _key: "00af18309329", _type: "image", url: "<https://cdn.sanity.io/images/ax2b1emw/production/efd90ba5e6942927a7bb04b72e8b7bb74494dd63-4896x3264.jpg>", … }

2: Object { _key: "7a8246b69363", _type: "break", break: true }

3: Object { _key: "d2288b5aa74b", _type: "block", style: "normal", … }

4: Object { _key: "9f0f081a7cf6", _type: "block", style: "normal", … }

5: Object { _key: "02cd832b3f4f", _type: "block", style: "normal", … }

6: Object { _key: "347006c9a303", _type: "doubleImage", leftImage: {…}, … }

_key: "347006c9a303"

_type: "doubleImage"

leftImage: Object { _type: "image", asset: {…} }

_type: "image"

asset: Object { _ref: "image-639eb5a2780601edb6dc19bf20f52efb2c37588f-4500x3000-jpg", _type: "reference" }

_ref: "image-639eb5a2780601edb6dc19bf20f52efb2c37588f-4500x3000-jpg"

_type: "reference"

<prototype>: Object { … }

<prototype>: Object { … }

rightImage: Object { _type: "image", asset: {…} }
I think you need something like:
*[_type == "entry"] | order(date desc, _updatedAt desc) {
  _id,
  title,
  date,
  excerpt,
  content[]{
    ...,
    _type == "image" => { 
      'url': asset->url,
      ...,
    },
    _type == "doubleImage" => { 
      ...,
      'leftImageUrl':leftImage.asset->url,
      'rightImageUrl':rightImage.asset->url
    },
  },
  topics,
  "slug": slug.current,
}
Sidenote: when using the spread operator, make sure you put it above any fields your naming so you don't accidentally overwrite them.
TYSM! I will give this a go. I really appreciate the help! And thanks for the tip as well. That is definitely good to know. I hope you have a good weekend.
That worked! Thanks! This is for my first freelance project btw. I have enjoyed using Sanity!
Congrats on your first freelance project! Huge achievement! Have a good weekend as well!
Hey
user M
, I have a similar issue. But all I want to do is create an
excerpt
field that I can call in my front end as

{{project.excerpt}}
Ideally, the excerpt is the first 100 characters from a project.body.

*[_type == "article"] {
   "excerpt": array::join(string::split((pt::text(body)), "")[0..255], "") + "..."
}
This excerpt didn't work out for me.

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?