Hotspot Images in Sanity: From Schema to Responsive Delivery
Learn how Sanity’s hotspot‑enabled image pipeline lets you shift cropping and responsive design decisions from code to content. A step‑by‑step guide covers schema setup, GROQ querying, and client‑side URL building, plus trade‑offs to watch out for.
30 Sept 2025, 15:15 UTC

Why Hotspot‑Based Images Matter
When a marketing team wants a headline image that looks great on a phone, tablet, and desktop, the simplest approach is to upload several crops. In Sanity, the image pipeline lets you keep a single asset and let the editor pick a hotspot—the focus area—and then let the image URL builder generate the right crop for each breakpoint. This shifts the “where to look” decision from code to content, giving editors control while the front‑end stays agnostic.
Schema First: Enabling Hotspot in Studio
Hotspot support is not enabled by default. In a Studio v3 project you add it via the imageHotspot option in the schema. Below is a minimal schema for a page that contains a Portable Text block with an image that can be hotspot‑edited.
export default {
name: "page",
type: "document",
title: "Page",
fields: [
{
name: "title",
type: "string",
title: "Title",
},
{
name: "body",
type: "array",
of: [
{
type: "block",
},
{
type: "image",
options: {
hotspot: true,
},
fields: [
{name: "alt", type: "string", title: "Alt text"},
],
},
],
},
],
}
Once hotspot: true is set, the Studio UI shows a drag‑and‑drop hotspot overlay when an image is selected. The hotspot is stored as hotspot.x, hotspot.y, hotspot.width, and hotspot.height on the asset document.
Pulling Asset Metadata with GROQ
To build a responsive image set you need the asset ID and the hotspot data. A GROQ query that returns the first image in the body block and its hotspot looks like this:
*[_type == "page" && slug.current == $slug][0] {
title,
"heroImage": body[0]._type == "image" => body[0] {
asset->{
_id,
url,
hotspot
}
}
}
Run this query from a Sanity client or the GraphQL Playground. The result will include a nested heroImage object with the asset URL and hotspot JSON. In a real project you would map over the body array to find all images, but the pattern is the same.
Building Responsive URLs on the Client
Sanity’s image URL builder is a tiny JavaScript helper that turns the asset ID and parameters into a full URL. In a React component you might write:
import {imageUrlBuilder} from "@sanity/image-url";
import sanityClient from "@sanity/client";
const client = sanityClient({
projectId: "YOUR_PROJECT_ID",
dataset: "production",
useCdn: true,
});
const builder = imageUrlBuilder(client);
function buildImageUrl(asset, params) {
return builder
.image(asset)
.width(params.w)
.height(params.h)
.fit(params.fit || "crop")
.auto(params.auto || "format")
.url();
}
// Example usage
const hero = data.heroImage.asset;
const url = buildImageUrl(hero, {w: 800, h: 600});
Notice that the fit defaults to crop, which respects the hotspot. If you want to ensure the hotspot stays in view, you can add crop=hotspot to the parameters. The builder automatically appends the _id and hotspot data to the URL query string.
Practical Example: Responsive Hero Section
Below is a simplified React component that renders the hero image at three breakpoints. The component pulls the hotspot metadata from the query, then builds three URLs with different widths.
function Hero({asset}) {
const sizes = [
{w: 400, h: 300}, // mobile
{w: 800, h: 600}, // tablet
{w: 1200, h: 900}, // desktop
];
const srcSet = sizes
.map(s => `${buildImageUrl(asset, s)} ${s.w}w`)
.join(", ");
return (
<img
src={buildImageUrl(asset, sizes[1])}
srcSet={srcSet}
sizes="(max-width: 600px) 100vw, 800px"
alt={asset.alt}
loading="lazy"
/>
);
}
To verify the image is rendered correctly:
- Open the page in a browser and inspect the
imgtag. - Check the network tab for requests to
cdn.sanity.iowith the expectedw,h, andcrop=hotspotparameters. - Resize the viewport and confirm the correct image variant is chosen.
Trade‑offs and Limitations
- Editorial Coupling: Editors must decide hotspot positions that align with the front‑end layout. Misaligned hotspots can break design intent.
- Image Pipeline Dependence: All transforms go through Sanity’s CDN. If you need a custom format or advanced compression, you may hit limits or incur extra latency.
- Parameter Versioning: The URL builder’s parameter names (e.g.,
fit,auto) can change between releases. Keep your build scripts up to date or guard against breaking changes. - Caching Complexity: Because URLs include transform parameters, you must ensure your CDN caches each variant. Forgetting to set proper cache headers can lead to repeated processing.
Actionable Checklist
- Add
hotspot: trueto all image fields that will be used responsively. - Define a GROQ query that dereferences
asset->hotspotfor each image. - Use the image URL builder on the client to generate URLs with
crop=hotspotand desired dimensions. - Test by inspecting network requests and verifying hotspot alignment across breakpoints.
- Document hotspot conventions for editors (e.g., always center on a character in a headline).
By moving hotspot decisions into the content model, you free your front‑end from hard‑coded crop coordinates, reduce asset duplication, and give editors a visual lever to control layout. Just remember that this power comes with a need for disciplined schema design and careful testing of image transforms.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.