> ## Documentation Index
> Fetch the complete documentation index at: https://docs.spaportal.cz/llms.txt
> Use this file to discover all available pages before exploring further.

# Images

> Render responsive hotel, room type, and visit type images from API v1 and v2.

Hotel and room type responses include responsive image metadata in API v1 and
v2. API v1 also exposes it for visit types. Embedded room types and visit types
use the same fields as their top-level responses.

## API v2 response shape

Every image contains all six fields:

```json theme={null}
{
  "url": "https://files.example.com/production/hotels/example/photo.jpg",
  "thumbnailUrl": "https://files.example.com/production/thumbnails/hotels/example/photo.webp",
  "width": 2400,
  "height": 1600,
  "alt": {
    "en": "Spa hotel exterior"
  },
  "variants": {
    "w480": "https://files.example.com/production/thumbnails/v2/hotels/example/generation/w480.webp",
    "w960": "https://files.example.com/production/thumbnails/v2/hotels/example/generation/w960.webp",
    "w1440": "https://files.example.com/production/thumbnails/v2/hotels/example/generation/w1440.webp",
    "w1920": "https://files.example.com/production/thumbnails/v2/hotels/example/generation/w1920.webp"
  }
}
```

| Field             | Meaning                                                                                  |
| ----------------- | ---------------------------------------------------------------------------------------- |
| `url`             | Original image URL. Use it for a full-size view and as the final fallback.               |
| `thumbnailUrl`    | Deprecated legacy preview URL. It remains available throughout API v2 and can be `null`. |
| `width`, `height` | Intrinsic dimensions of the oriented original, or `null` when unavailable.               |
| `alt`             | Localized alternative text selected by `Accept-Language`.                                |
| `variants`        | Available WebP URLs keyed by target width.                                               |

## API v1 response shape

API v1 puts the first image directly on each hotel, room type, or visit type.
Where `image` and `thumbnail` already exist, their values remain unchanged. The
responsive metadata is additive:

```json theme={null}
{
  "image": "https://files.example.com/production/hotels/example/photo.jpg",
  "thumbnail": "https://files.example.com/production/thumbnails/hotels/example/photo.webp",
  "width": 2400,
  "height": 1600,
  "alt": {
    "cs_CZ": "Průčelí lázeňského hotelu"
  },
  "variants": {
    "w480": "https://files.example.com/production/thumbnails/v2/hotels/example/generation/w480.webp",
    "w960": "https://files.example.com/production/thumbnails/v2/hotels/example/generation/w960.webp",
    "w1440": "https://files.example.com/production/thumbnails/v2/hotels/example/generation/w1440.webp",
    "w1920": "https://files.example.com/production/thumbnails/v2/hotels/example/generation/w1920.webp"
  }
}
```

| API v2 image field | API v1 entity field |
| ------------------ | ------------------- |
| `url`              | `image`             |
| `thumbnailUrl`     | `thumbnail`         |
| `width`            | `width`             |
| `height`           | `height`            |
| `alt`              | `alt`               |
| `variants`         | `variants`          |

In API v1, all six fields describe only the first image. When the entity has no
image, `image`, `thumbnail`, `width`, and `height` are `null`, `variants` is an
empty object, and `alt` contains the requested locale keys with `null` values.

## Build a responsive image

Use only the variant URLs returned by the API. Do not construct a URL for a
missing width. Images are never enlarged, so an 1100-pixel original has
`w480` and `w960`, but no larger variants. For API v1, pass the entity itself;
for API v2, pass one item from the `images` array and normalize the two legacy
field names first.

```js theme={null}
const widths = [480, 960, 1440, 1920];

const image = {
  url: item.url ?? item.image ?? null,
  thumbnailUrl: item.thumbnailUrl ?? item.thumbnail ?? null,
  width: item.width,
  height: item.height,
  alt: item.alt,
  variants: item.variants ?? {},
};

const srcset = widths
  .flatMap((width) => {
    const url = image.variants[`w${width}`];
    return url ? [`${url} ${width}w`] : [];
  })
  .join(", ");

const src =
  image.variants.w960 ?? image.variants.w480 ?? image.thumbnailUrl ?? image.url;
```

Set `srcset` only when the resulting string is non-empty. Set `sizes` to the
actual layout slot, for example `(max-width: 768px) 100vw, 50vw`. The browser
then selects the best available variant for the viewport and device pixel
density.

Use non-null `width` and `height` as the HTML intrinsic dimensions. They reserve
the correct aspect ratio before the image loads. Do not replace them with the
CSS slot size.

```html theme={null}
<img
  src="<selected src>"
  srcset="<generated srcset>"
  sizes="(max-width: 768px) 100vw, 50vw"
  width="2400"
  height="1600"
  alt="Spa hotel exterior"
  loading="lazy"
/>
```

Use `loading="eager"` and `fetchpriority="high"` only for the single image that
is the page's likely largest contentful paint (LCP). Lazy-load images outside
the initial viewport.

## Empty variants and fallbacks

An empty `variants` object means that no responsive variant is available. It
does not mean that processing is still pending. Omit `srcset` and use
`thumbnailUrl ?? url` as `src`. For the unnormalized API v1 shape, the same
fallback is `thumbnail ?? image`.

There are two possible cases:

* A small original can have known `width` and `height` but no variant because
  its width is below 480 pixels.
* An unavailable legacy image has `width: null`, `height: null`, and
  `variants: {}`.

As a final error fallback, remove `srcset` and try `thumbnailUrl`, then `url`.
This is useful if a cached client encounters a missing variant, but it does not
replace normal HTTP error monitoring.

## Alternative text

`alt` follows `Accept-Language` ([API v1](/api/v1/localization), [API
v2](/api/localization)). The response contains the requested locale keys:

* A missing or `null` hotel image translation falls back to the localized
  hotel name.
* A missing or `null` room image translation falls back to the localized room
  category, or `null` when that category translation is unavailable.
* A missing or `null` visit type image translation falls back to the localized
  visit type name.
* An explicit empty string remains `""`. Preserve it when the image is
  decorative.
* A non-empty stored value is trimmed.

The API provides recommended alternative text. Your client can still use
`alt=""` when the image is decorative or redundant in its rendered context.

## Compatibility

The responsive fields are additive in both API versions. In API v2, existing
`url` and `thumbnailUrl` values retain their behavior, and `thumbnailUrl`
remains present as a nullable field. In API v1, existing hotel and room type
`image` and `thumbnail` values retain their behavior. Visit types now expose
the same first-image fields.

See the API v2 [Hotel](/api/objects/hotel) and [Room
type](/api/objects/room-type) object references, or the API v1 [Hotels
endpoint](/api/v1/reference/catalog/get-hotels), [Hotel
endpoint](/api/v1/reference/catalog/get-hotel), and [Visit types
endpoint](/api/v1/reference/catalog/get-visit-types).
