Annotating a Hotel offering Rooms with the new version 3.1

With the version 3.1, brings a lot of new annotation power to hotels. Previously accommodation providers were able to annotate the core data of their business, like name, phone, address and more, but the newly released version 3.1 brings that to a new level and allows the annotation of rooms, features and services and even lets the accommodation owners annotate their room offers on the website. This article shows how this is done on a short JSON-LD example.

The example starts with the straight forward definition of the hotel with some properties like name, URL, address and others. The property makesOffer requires an Offer which comes with a property itemOffered, which has our special attention here.

The itemOffered requires, as stated in the documentation, either a Product or Service. The alleged problem: HotelRoom is neither. Here comes up with the concept of Multiple Typed Entities (MTE). One might think now “What is new about that, Hotel itself is an Organization and a Place”, but this is different. In the case of the HotelRoom we have to make a multi typing on the instance level instead of the vocabulary level.

This works simply by setting the @type of our annotated hotel room to HotelRoom AND Product – in the JSON-LD implementation we use an array for that. The rest of the example is straight forward: the room gets a bed, a description, a name and values for occupancy.

    "@context": "",
    "@type": "Hotel",
    "name": "Landgasthof Adler",
    "openingHours": "We-Mo 10:00-20:00",
    "paymentAccepted": "Cash, credit card",
    "url": "",
    "address": {
        "@type": "PostalAddress",
        "addressCountry": "Austria",
        "addressLocality": "Hinterhornbach",
        "addressRegion": "Tirol",
        "postalCode": "6642",
        "streetAddress": "Hinterhornbach 17"
    "makesOffer": {
        "@type": "Offer",
        "availability": "InStock",
        "name": "Enzian Room",
        "itemOffered": {
            "@type": ["HotelRoom", "Product"],
            "bed": {
                "@type": "BedDetails",
                "numberOfBeds": 1
            "description": "Double Room with Shower",
            "name": "Enzian Room",
            "numberOfRooms": 1,
            "occupancy": {
                "@type": "QuantitativeValue",
                "maxValue": 3,
                "minValue": 1

For further information about, follow their blog and brows their GitHub issues.

Annotating ski resorts, lifts and slopes with is awesome. It provides useful terms to annotate a great variety of entities on the web. Events, articles, products, people, hotels… for almost every item the modern webmaster wants to annotate, there’s a class for it. But since the initiative, driven by Bing, Google, Yahoo! and Yandex , is reatively young (2011), it’s pretty easy to hit the wall. That is what happens if one tries to annotate the ski lifts and slopes of a ski resort. The class is a subclass of but does not introduce any new attributes. This article describes the approach to extend the vocabulary by two new classes and some new attributes to meet the requirements for the proper annotation of ski resorts.

This article describes a extension which is currently under review by the steering committee and not yet part of!

What’s new

Ski resort

To properly annotate a ski resort, apart from the properties inherited from LocalBusiness, Place, Organization and Thing, we need two new properties to add lifts and slopes. So we introduced hasSkiLift which expects the newly introduced type SkiLift and hasSkiSlope which expects the newly introduced type SkiSlope.

Ski lift

The type SkiLift is, like the ski resort itself, inherited from SportsActivityLocation. The new attributes describe the length, the elevation at the start (elevationStart) and the elevation at the end (elevationEnd) of the lift, the type (liftType: T-Bar lift, chair lift or cable car), the number of stops (numberOfStops) and the transport capacity (transportCapacity).

Ski slope

The newly introduced SkiSlope is inherited from SportsActivityLocation as well. The newly introduced attributes identify the ski slope by a number (slopeNumber), describe the difficulty and the length.


The following example uses Microdata and describes a ski resort with two ski lifts and three ski slopes.

<div itemtype="" itemid="" itemscope>
  <meta itemprop="name" content="Familienskilifte Stanzach" />
  <link itemprop="sameAs" href="" />
  <link itemprop="sameAs" href="" />
  <link itemprop="image" href="" />
  <div itemprop="hasSkiLift" itemtype="" itemscope>
    <meta itemprop="length" content="550" />
    <meta itemprop="transportCapacity" content="2" />
    <meta itemprop="numberOfStops" content="2" />
    <meta itemprop="elevationEnd" content="1190" />
    <meta itemprop="elevationStart" content="940" />
    <meta itemprop="name" content="Stoamandllift" />
    <meta itemprop="liftType" content="T-bar lift" />
  <div itemprop="hasSkiSlope" itemtype="" itemscope>
    <meta itemprop="length" content="1330" />
    <meta itemprop="name" content="Familienabfahrt" />
    <meta itemprop="difficulty" content="blue" />
    <meta itemprop="slopeNumber" content="1a" />
  <div itemprop="hasSkiSlope" itemtype="" itemscope>
    <meta itemprop="length" content="1820" />
    <meta itemprop="name" content="Rennstrecke" />
    <meta itemprop="difficulty" content="red" />
    <meta itemprop="slopeNumber" content="1b" />
  <div itemprop="hasSkiSlope" itemtype="" itemscope>
    <meta itemprop="length" content="2575" />
    <meta itemprop="name" content="Wald Verbindungslift" />
    <meta itemprop="difficulty" content="Skiroute" />
    <meta itemprop="slopeNumber" content="2" />

The same example in JSON-LD looks like this:

<script type="application/ld+json">
       "@context": "",
       "@type": "SkiResort",
       "@id": "",
       "name": "Familienskilifte Stanzach",
       "sameAs": [
       "image": "",
       "hasSkiLift": {
           "@type": "SkiLift",
           "name": "Stoamandllift",
           "liftType": "T-bar lift",
           "transportCapacity": "2",
           "elevationStart": "940",
           "elevationEnd": "1190",
           "length": "550",
           "numberOfStops": "2"
       "hasSkiSlope": [{
           "@type": "SkiSlope",
           "name": "Familienabfahrt",
           "slopeNumber": "1a",
           "length": "1330",
           "difficulty": "blue"
           "@type": "SkiSlope",
           "name": "Rennstrecke",
           "slopeNumber": "1b",
           "length": "1820",
           "difficulty": "red"
           "@type": "SkiSlope",
           "name": "Wald Verbindungslift",
           "slopeNumber": "2",
           "length": "2575",
           "difficulty": "Skiroute"

Documentation and Discussion

The full documentation (in progress) can be found at: and the discussion , on the extension as well as on the integration progress in can be found on Github in the pull request: