How to use hotspot and crop attributes for images in Sanity queries?
I understand the confusion with hotspot and crop data! The key thing to know is that when you query an image with hotspot/crop data, that data is automatically included in the image object, but how you use it depends on which tool you're working with.
Let me break down the most common scenarios:
Using @sanity/image-url (Image URL Builder)
When you use the image URL builder, the hotspot and crop data are automatically applied when you pass the entire image object to it:
import imageUrlBuilder from '@sanity/image-url'
const builder = imageUrlBuilder(sanityClient)
function urlFor(source) {
return builder.image(source) // Pass the whole image object
}
// In your GROQ query, just get the image field normally:
// *[_type == "post"][0].mainImage
const imageUrl = urlFor(image)
.width(400)
.height(300)
.url()The builder will automatically read the hotspot and crop properties from your image object and apply them to the transformations.
Common Issue: Not Passing the Complete Image Object
The most common mistake is only passing the asset reference instead of the entire image object. Make sure your GROQ query includes the full image field:
// ✅ Correct - gets the whole image object including hotspot/crop
*[_type == "post"][0]{
mainImage
}
// ❌ Wrong - only gets the asset reference
*[_type == "post"][0]{
"imageUrl": mainImage.asset->url
}Manual Implementation with CSS
If you're using frameworks like Next.js where the hotspot doesn't seem to work automatically (a common issue), you can manually apply the hotspot using CSS:
function getPositionFromHotspot(hotspot) {
if (!hotspot || !hotspot.x || !hotspot.y) return "center";
return `${hotspot.x * 100}% ${hotspot.y * 100}%`;
}
// Usage with Next.js Image
<Image
src={urlForImage(image).url()}
alt={image.alt}
fill
style={{
objectFit: 'cover',
objectPosition: getPositionFromHotspot(image?.hotspot)
}}
/>Enabling Hotspot in Your Schema
Make sure hotspot is enabled in your schema first:
{
name: 'mainImage',
type: 'image',
options: {
hotspot: true // This enables the hotspot feature
}
}What the Hotspot Data Looks Like
When you query an image with hotspot, the data structure looks like this:
{
_type: 'image',
asset: { _ref: '...', _type: 'reference' },
hotspot: {
x: 0.5, // 0-1 (percentage from left)
y: 0.3, // 0-1 (percentage from top)
height: 0.4,
width: 0.4
},
crop: {
top: 0,
bottom: 0,
left: 0,
right: 0
}
}The most likely issue you're facing is either not passing the complete image object to the URL builder, or working with a frontend framework that needs the manual CSS approach. If you're using the image URL builder correctly with the full image object, the hotspot should work automatically without any extra code!
Show original thread36 replies
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.