How to grab image metadata from images inserted into Content blocks?

7 replies
Last updated: Sep 28, 2020
I’d really like to be able to grab image metadata from images inserted into Content blocks, but all I seem to be able to get back is a reference. How can I expand references contained inside portable text blocks?
AI Update

You can expand references inside Portable Text blocks, including image assets, by using GROQ's reference access operator (->) to dereference them in your query.

When you have images in your Portable Text content blocks, they're stored as references to asset documents. To get the full image metadata (dimensions, palette, LQIP, etc.), you need to expand those references when querying.

Here's how to do it:

*[_type == "article"]{
  body[]{
    ...,
    _type == "image" => {
      ...,
      asset->
    }
  }
}

This query:

  • Iterates through each item in the body array with body[]
  • Uses the spread operator ... to include all existing properties
  • Conditionally expands image blocks with _type == "image" =>
  • Dereferences the asset with asset-> to get the full asset document including metadata

If you only need specific metadata fields, you can project them:

*[_type == "article"]{
  body[]{
    ...,
    _type == "image" => {
      ...,
      asset->{
        _id,
        url,
        metadata {
          dimensions,
          palette,
          lqip
        }
      }
    }
  }
}

This also works for references in markDefs (like link annotations). For example, if you have reference annotations in your Portable Text:

*[_type == "article"]{
  body[]{
    ...,
    markDefs[]{
      ...,
      _type == "internalLink" => {
        ...,
        reference->
      }
    }
  }
}

The reference access operator documentation has more details on joining asset documents in Portable Text queries. The key is using the -> operator after any reference field to fetch the complete referenced document instead of just getting back the _ref ID.

Hi Andrew, have you tried something like this? If
content
is your block content field:
*[_type == "post"]{
  ...,
  "content": content[] {
    ...select(
      _type == "image" => {
        ...,
        "asset": asset->
      } 
    )
  }
}
Hi Andrew, have you tried something like this? If
content
is your block content field:
*[_type == "post"]{
  ...,
  "content": content[] {
    ...select(
      _type == "image" => {
        ...,
        "asset": asset->
      } 
    )
  }
}
You have awesome timing, I was just cobbling together something like this from what I could deconstruct from https://www.sanity.io/docs/presenting-block-text — but you helped me get the last piece in place
oddly enough, going off the examples, I ended up forming a query much like what you’ve got up there, except without the
…select
, but the the same contents inside the parentheses. It doesn’t seem to make a difference whether I use the
select
operator, I’m curious what that does here?
(also thank you! 🙏 )
Glad it’s working! If you’re not using
select
, you might be using the short-hand notation instead. Check out the part where it says:
// Projections also have syntactic sugar for inline conditionals
https://www.sanity.io/docs/query-cheat-sheet#conditionals-64a36d80be73
Brilliant. Makes perfect sense.

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?