This guide outlines how to tag your website with [microdata](https://developers.google.com/hotels/hotel-prices/structured-data/generic-crawler-guide#price-declaration)
and [navigation attributes](https://developers.google.com/hotels/hotel-prices/structured-data/generic-crawler-guide#nav-implementation) so Google's price accuracy
crawler can automatically navigate your booking funnel and validate your room
rates.

> [!NOTE]
> **Note:** Throughout this guide, the terms **crawler** and **validator** refer specifically to Google's generic hotel price accuracy validator crawler.

> [!IMPORTANT]
> **Key Point:** The crawler verifies rates by sequentially evaluating your booking funnel, simulating a user journey. It expects each intermediate page to provide one or more navigation elements ([`data-nav-*`](https://developers.google.com/hotels/hotel-prices/structured-data/generic-crawler-guide#nav-implementation)) to advance to the next step. The journey concludes on the final page, marked with [`data-nav-stage-final="true"`](https://developers.google.com/hotels/hotel-prices/structured-data/generic-crawler-guide#final-stage-indicator), where the crawler extracts the total stay price from a single [microdata-tagged](https://developers.google.com/hotels/hotel-prices/structured-data/generic-crawler-guide#price-declaration) offer element. The crawler cannot provide user inputs (such as guest names or payment details); rates must be accessible using clicks alone. For the complete technical specification of all available structured data properties (including itemized taxes, fees, and room details), see the [hotel price structured data reference](https://developers.google.com/hotels/hotel-prices/structured-data/hotel-price-structured-data) .

*** ** * ** ***

## Conceptual crawler flow

The following sequence illustrates how the crawler navigates a typical booking
funnel, handling dynamic loading states and identifying critical actions.

### 🗺️ Quick flow overview

- **🔗 Phase 1: Google surface** --- Crawler accesses the [Dynamic Landing Page URL](https://developers.google.com/hotels/hotel-prices/dev-guide/pos-urls) (configured on Google based on your template), landing on your site just as a real user would.
- **🛬 Phase 2: Landing page** --- Crawler lands on the partner site (`data-nav-stage="landing"`).
- **🖱️ Phase 3: Navigation** --- Crawler executes [mandatory interactions](https://developers.google.com/hotels/hotel-prices/structured-data/generic-crawler-guide#nav-implementation) (clicks, selections) declared using `data-nav-*` attributes.
- **🏁 Phase 4: Final page** --- Crawler reaches the [final accessible page](https://developers.google.com/hotels/hotel-prices/structured-data/generic-crawler-guide#final-stage-indicator) (`data-nav-stage-final="true"`).
- **📊 Phase 5: Price extraction** --- Crawler extracts the [microdata-tagged](https://developers.google.com/hotels/hotel-prices/structured-data/generic-crawler-guide#price-declaration) price and validates total stay cost.

> [!NOTE]
> **Note:** This flow is a conceptual example. Partners should implement the combination of navigation and microdata tagging that is appropriate for their specific website architecture and booking flow.

### Step 1: landing page (hotel selection or optional upsell page)

The crawler visits the **landing page URL** (the page where the user lands on
the partner site after clicking on Google items). For details on configuring
landing page parameters to ensure the correct rate is selected, see
[variables and conditions](https://developers.google.com/hotels/hotel-prices/dev-guide/pos-urls).

**State A: loading screen**

A loading indicator mask is transiently visible. The
crawler waits for this nav tag to disappear (max 15 seconds).

    <body data-nav-stage="landing">
      <!-- Loading indicator: Crawler waits for this to disappear (max 15s) -->
      <div data-nav-loading-indicator="true">Loading Page...</div>
    </body>

**State B: page loaded**

Once the loading indicator disappears, the page content
is loaded. The crawler locates and clicks the critical path element to advance.

> [!NOTE]
> **Note:** If multiple rates are displayed, only the rate corresponding to the itinerary the **user selected on Google** should be tagged for the crawler (either preselected or navigational tags for selecting the rate, corresponding to rate-id or other relevant variables in landing page URL parameters).

    <body data-nav-stage="landing">
      <!-- Ignored: Crawler skips non-selected rates -->
      <div class="hotel-result">
        <h3>Grand Hotel - Basic Room</h3>
        <button>View Rates</button>
      </div>

      <!-- critical path: crawler clicks this to advance -->
      <div class="hotel-result selected-rate">
        <h3>Grand Hotel - Deluxe Suite</h3>
        <button data-nav-criticalpath="true"
                data-nav-interactiontype="CLICK"
                data-nav-interactionorder="1">
          View Rates
        </button>
      </div>
    </body>

### Step 2: optional intermediate page (room or option selection)

The crawler arrives at the rate selection page.

**State A: loading screen**

A spinner appears while rates are fetched.

    <body data-nav-stage="room-selection">
      <div data-nav-loading-indicator="true">Fetching Rates...</div>
    </body>

**State B: page loaded**

After loading finishes, the crawler might interact with
multiple elements in sequence before proceeding. Only **mandatory** interactions
(e.g., agreeing to mandatory terms or selecting required configurations based on
user selection on Google or min mandatory price path) should be tagged.

    <body data-nav-stage="room-selection">
      <!-- Step 1: mandatory interaction (e.g., select bed configuration) -->
      <div class="rate-option">
        <p>Deluxe Suite</p>

        <!-- Note: Either the value selected by the user on Google should be pre-selected,
             or navigation elements must be provided so the crawler can select it. -->
        <div class="bed-selection">
          <button data-nav-criticalpath="true"
                  data-nav-interactiontype="CLICK"
                  data-nav-interactionorder="1">
            Select Queen Bed
          </button>
          <button>Select King Bed</button>
        </div>
      </div>

      <!-- Step 2: mandatory interaction (e.g., mandatory insurance opt-out or agreement) -->
      <div class="mandatory-notice">
        <label>
          <input type="checkbox"
                 data-nav-criticalpath="true"
                 data-nav-interactiontype="CLICK"
                 data-nav-interactionorder="2">
          I agree to the non-refundable dynamic pricing waiver.
        </label>
      </div>

      <!-- Step 3: Continue to checkout -->
      <button data-nav-criticalpath="true"
              data-nav-interactiontype="CLICK"
              data-nav-interactionorder="3">
        Continue Reserving
      </button>
    </body>

### Step 3: final crawling page (price validation / booking summary)

The crawler reaches the **final accessible page** (the final page before user
personal or payment information entry). It verifies the `data-nav-stage-final`
flag is true. This signals the crawler to extract the microdata-tagged price
after any remaining navigations. **Navigation tags are always interacted with
first before extracting the price.**

Main item scopes should be a **cotype of Hotel and LodgingReservation** (e.g.,
`itemtype="https://schema.org/Hotel https://schema.org/LodgingReservation"`).
For backward compatibility, we also accept a parent `Hotel` scope that contains
a child element cotyped as both `Offer` and `LodgingReservation` (for example,
`<div itemprop="makesOffer" itemscope itemtype="https://schema.org/Offer
https://schema.org/LodgingReservation">`). Only one `Hotel` and `Offer` under
that `Hotel` should be tagged on the page.

- This example shows only the mandatory total price tagging, recommended for
  simplicity. {Simple Total Price}

      <!-- End of Scope comments identify container boundaries -->
      <body data-nav-stage="checkout" data-nav-stage-final="true">

        <!-- Booking Summary Cart Scope (Hotel + LodgingReservation) -->
        <div class="booking-summary" itemscope itemtype="https://schema.org/Hotel https://schema.org/LodgingReservation">

          <!-- Hotel Identifier (Can be hidden meta tag) -->
          <meta itemprop="identifier" content="grand-hotel-001" />

          <h2 itemprop="name">Grand Hotel</h2>

          <!-- Visible Stay Dates & Occupancy (checkinDate / checkoutDate are also acceptable) -->
          <p>
            Check-in: <span itemprop="checkinTime" content="2026-08-10">Aug 10, 2026</span> |
            Check-out: <span itemprop="checkoutTime" content="2026-08-15">Aug 15, 2026</span> |
            Guests: <span itemprop="numAdults">2</span> Adults, <span itemprop="numChildren">1</span> Child
          </p>

          <!-- Offer Scope -->
          <div class="cart-details" itemprop="makesOffer" itemscope itemtype="https://schema.org/Offer">

            <!-- Compound Price Scope -->
            <div itemprop="priceSpecification" itemscope itemtype="https://schema.org/CompoundPriceSpecification">

              <div class="total-line">
                <span>Total Stay (Taxes Included):</span>
                <!-- The crawler extracts this final rate as total price -->
                <span itemprop="price">440.00</span>
                <meta itemprop="priceCurrency" content="USD" />
              </div>

            </div> <!-- End of CompoundPriceSpecification Scope -->
          </div> <!-- End of Offer Scope -->
        </div> <!-- End of Hotel/LodgingReservation Scope -->

      </body>

- This example shows the total price alongside itemized breakdowns (Base Rate,
  Fees). {Total Price + Breakdown}

      <!-- End of Scope comments identify container boundaries -->
      <body data-nav-stage="checkout" data-nav-stage-final="true">

        <!-- Booking Summary Cart Scope (Hotel + LodgingReservation) -->
        <div class="booking-summary" itemscope itemtype="https://schema.org/Hotel https://schema.org/LodgingReservation">

          <!-- Hotel Identifier (Can be hidden meta tag) -->
          <meta itemprop="identifier" content="grand-hotel-001" />

          <h2 itemprop="name">Grand Hotel</h2>

          <!-- Visible Stay Dates & Occupancy (checkinDate / checkoutDate are also acceptable) -->
          <p>
            Check-in: <span itemprop="checkinTime" content="2026-08-10">Aug 10, 2026</span> |
            Check-out: <span itemprop="checkoutTime" content="2026-08-15">Aug 15, 2026</span> |
            Guests: <span itemprop="numAdults">2</span> Adults, <span itemprop="numChildren">1</span> Child
          </p>

          <!-- Offer Scope -->
          <div class="cart-details" itemprop="makesOffer" itemscope itemtype="https://schema.org/Offer">

            <!-- Compound Price Scope -->
            <div itemprop="priceSpecification" itemscope itemtype="https://schema.org/CompoundPriceSpecification">

              <div class="line-item">
                <span>Base Rate (2 Nights):</span>
                <!-- Unit Price Scope for Base -->
                <span itemprop="priceSpecification" itemscope itemtype="https://schema.org/UnitPriceSpecification">
                  <span itemprop="price">400.00</span>
                  <meta itemprop="priceCurrency" content="USD" />
                </span> <!-- End of UnitPriceSpecification Scope -->
              </div>

              <div class="line-item">
                <span>Resort Fee:</span>
                <!-- Unit Price Scope for Fee -->
                <span itemprop="priceSpecification" itemscope itemtype="https://schema.org/UnitPriceSpecification">
                  <span itemprop="price">40.00</span>
                  <meta itemprop="priceCurrency" content="USD" />
                </span> <!-- End of UnitPriceSpecification Scope -->
              </div>

              <div class="total-line">
                <span>Total Stay:</span>
                <!-- The crawler extracts this final rate as total price -->
                <span itemprop="price">440.00</span>
                <meta itemprop="priceCurrency" content="USD" />
              </div>

            </div> <!-- End of CompoundPriceSpecification Scope -->
          </div> <!-- End of Offer Scope -->
        </div> <!-- End of Hotel/LodgingReservation Scope -->

      </body>

*** ** * ** ***

## 1. Navigation implementation (`data-nav-*`)

Use custom `data-nav-*` HTML attributes to annotate interactive elements and
declare funnel stages so the crawler can traverse your booking flow.

### 1.1 Top-of-page stage declaration (`data-nav-stage`)

Every page in your booking funnel that displays rates should declare its stage,
attached to the `<body>` tag or a primary wrapper tag (such as `<div>`,
`<section>`, or `<main>`). This tells the crawler which stage of the booking
flow is active and assists with troubleshooting issues later on.

- **`data-nav-stage`** *(Recommended):* Declares the active funnel stage. While not strictly required, specifying names (for example, `"landing"`, `"room-selection"`, `"checkout"`, `"ready-for-payment"`) helps identify the active stage during validation.

### 1.2 Final stage indicator (`data-nav-stage-final`)

On the final page displaying prices prior to user personal or payment
information entry, add the final-stage flag to your top-of-page container
alongside a stage declaration (for example,
`data-nav-stage="ready-for-payment"`).

- **`data-nav-stage-final`** *(Required for price validation pages):* Set to `"true"` (`data-nav-stage-final="true"`) on the final page of the booking funnel that crawler can access . This signals that after all required navigation steps are complete, the crawler should read the price from this page.

> [!IMPORTANT]
> **Key Point:** If a page isn't the final price validation stage, it must include a properly tagged navigation item (button or link, or other interaction elements). The crawler will continue navigating until it reaches a page marked with `data-nav-stage-final="true"`, or it returns an error if no navigation elements are found.

### 1.3 Critical path interaction attributes

On intermediate pages, tag the interactive elements (buttons or links) that
advance the user along the booking critical path. If multiple actions are
required on the same page, specify the execution order. The crawler follows the
specified order before attempting to extract the price on the final page.

| Attribute | Required Value | Purpose |
|---|---|---|
| **`data-nav-criticalpath`** | `"true"` | Marks the mandatory button/link the crawler must click to advance. |
| **`data-nav-interactiontype`** | `"CLICK"` | Declares the interaction action. `CLICK` is for buttons/links. |
| **`data-nav-interactionorder`** | `"1"`, `"2"`, ... | Declares the execution sequence if multiple actions are required on the same page. |
| **`data-nav-loading-indicator`** | `"true"` | Marks an element that indicates a loading state (e.g., spinner). The crawler waits for this element to disappear before proceeding. |

#### Minimal navigation example

    <button data-nav-criticalpath="true"
            data-nav-interactiontype="CLICK"
            data-nav-interactionorder="1">
      Continue
    </button>

*** ** * ** ***

## 2. Price declaration (microdata)

On the final accessible page of your booking funnel (prior to personal or
payment information entry), tag the price offering (one price offer) with
microdata tags. Only one offer should be tagged on the page, indicating which
rate the crawler extracts, corresponding to the rate selected on Google before
the user lands on your website. For details on defining landing page parameters,
see [variables and conditions](https://developers.google.com/hotels/hotel-prices/dev-guide/pos-urls).

While Google fully supports the complete hierarchy in the
[hotel price structured data reference](https://developers.google.com/hotels/hotel-prices/structured-data/hotel-price-structured-data)

(including itemized base rates, individual taxes, fees, and room details),
Google also accepts a **simplified structured data tree** to make it easier for
you to tag hotel prices on your webpages.

The total stay price is mandatory for available rates. If an itinerary or room
is unavailable or sold out, declare `https://schema.org/SoldOut` under
`makesOffer` without a `priceSpecification`:

    <div itemprop="makesOffer" itemscope itemtype="https://schema.org/Offer">
      <meta itemprop="availability" content="https://schema.org/SoldOut"/>
      Sold Out
    </div>

For more information, see the
[`availability` property](https://developers.google.com/hotels/hotel-prices/structured-data/hotel-price-structured-data#availability)
specification.

### 2.1 Simplified structured data tree

To simplify tagging on your booking pages, you only need to declare the root
hotel and reservation container, stay dates (`YYYY-MM-DD`), occupancy, and a
single offer containing the total stay price:

    Hotel / LodgingReservation (Root Container)
    ├── identifier                   [Meta/Attribute] Hotel ID
    ├── name                         [Visible text] Hotel Name
    ├── checkinTime / checkoutTime   [Visible text with YYYY-MM-DD in content="..."] Stay Dates
    ├── numAdults / numChildren      [Visible text] Occupancy
    └── makesOffer (Offer)
        └── priceSpecification (CompoundPriceSpecification)
            ├── priceCurrency        [ISO Code, such as "USD"] Currency
            └── price                [Visible text] Total Stay Price (Taxes & Fees Included)

> [!IMPORTANT]
> **Key Point:** Both this simplified tree and the comprehensive hierarchy defined in the [hotel price structured data reference](https://developers.google.com/hotels/hotel-prices/structured-data/hotel-price-structured-data) are acceptable. Whichever structure you implement, elements must follow the required nesting hierarchy---microdata elements declared out of order or placed outside their parent container might be missed by the crawler.

### 2.2 Critical visibility rules

To ensure reliable price extraction, follow these visibility rules when tagging
your HTML:

- **Total stay price must be visible:** Tag the visible price number directly on the page using `itemprop="price"`. Don't use hidden metadata (`<meta>`) or attribute values (`value="..."` or `content="..."`) for the price number.
- **Machine-readable stay dates:** Tag visible stay dates on the page as much as possible. If needed, you can use the `content="..."` attribute on `<span>` elements to provide a standard `YYYY-MM-DD` format while displaying the visible date (for example, `<span itemprop="checkinTime"
  content="2026-08-10">August 10, 2026</span>`; `checkinDate` is also acceptable).
- **Non-visible fields:** Fields that aren't displayed directly on the page (such as the hotel ID or currency code) can use `<meta>` tags or `content="..."` attributes.

*** ** * ** ***

## 3. Examples

The following end-to-end examples show how to tag intermediate funnel steps and
final checkout pages with navigation attributes and microdata.

### Example 1: intermediate page with clickable button

The following snippet demonstrates an intermediate room selection page
(`room-selection`) with a single critical path action button tagged to advance
the flow:

    <body data-nav-stage="room-selection">
      <!-- Main page content -->
      <button class="btn-continue"
              data-nav-criticalpath="true"
              data-nav-interactiontype="CLICK"
              data-nav-interactionorder="1">
        Book This Room
      </button>
      <!-- Rest of the Main page content -->
    </body>

### Example 2: final price page with stage indicator and minimal microdata

The following snippet demonstrates the last page before payment
(`ready-for-payment`) where `data-nav-stage-final="true"` is declared on the
wrapper and the authoritative stay price is visibly exposed:

    <body data-nav-stage="ready-for-payment" data-nav-stage-final="true">

      <!-- Root Container: Co-Typed Hotel & LodgingReservation -->
      <div itemscope itemtype="https://schema.org/Hotel https://schema.org/LodgingReservation">

        <!-- Hotel Identifier (Can be hidden meta tag) -->
        <meta itemprop="identifier" content="grand-view-001" />
        <h1 itemprop="name">Grand View Hotel</h1>

        <!-- Visible Stay Dates & Occupancy -->
        <p>
          Check-in: <span itemprop="checkinTime" content="2026-08-10">Aug 10, 2026</span> |
          Check-out: <span itemprop="checkoutTime" content="2026-08-15">Aug 15, 2026</span> |
          Guests: <span itemprop="numAdults">2</span> Adults, <span itemprop="numChildren">1</span> Child
        </p>

        <!-- Single Minimal Rate Offer -->
        <div itemprop="makesOffer" itemscope itemtype="https://schema.org/Offer">
          <div itemprop="priceSpecification" itemscope itemtype="https://schema.org/CompoundPriceSpecification">

            <p class="summary-total">
              Total Stay Price (Taxes & Fees Included):

              <!-- 3-letter ISO Currency Code (can use content="" for hiding the 3-letter currency code while displaying a symbol) -->
              <span itemprop="priceCurrency" content="EUR">€</span>

              <!-- VISIBLE TOTAL STAY PRICE (Directly wrapped, no hidden attributes) -->
              <span itemprop="price">650.00</span>
            </p>

          </div>
        </div>

      </div>

    </body>

*** ** * ** ***

## 4. Verify your implementation

Before deploying your changes, test your markup and navigation tagging to ensure
the crawler can successfully validate your pricing data.

### 4.1 Verify price and microdata structure

You can use the
[Schema.org Validator](https://validator.schema.org/) or
[Google Rich Results Test](https://search.google.com/test/rich-results)
to inspect the microdata extracted from your page URL or HTML content. Verify
the extracted fields against the specification in the
[hotel price structured data reference](https://developers.google.com/hotels/hotel-prices/structured-data/hotel-price-structured-data)
, and ensure that your `itemprop="price"` element is a visible item on the page.

### 4.2 Verify navigation

To verify your tags, open **Browser Developer Tools** in Google Chrome by
right-clicking your webpage and selecting **Inspect** (or pressing `F12`) to
examine the HTML DOM. Find elements with `data-nav-*` attributes.

Confirm that your implementation meets the following navigation requirements:

- **Top-of-page stage is declared:** Every page in the booking flow includes `data-nav-stage="..."` on its `<body>` or root wrapper tag, and the final price page includes `data-nav-stage-final="true"`.
- **Critical path is complete:** Intermediate pages have their interactive elements (buttons or links) marked with `data-nav-criticalpath="true"`, `data-nav-interactiontype`, and `data-nav-interactionorder`. If multiple actions are present, ensure order numbers are set correctly.

### 4.3 Verify visibility and markup quality

Confirm that your microdata satisfies all structure and visibility requirements
(for details, see [simplified structured data tree](https://developers.google.com/hotels/hotel-prices/structured-data/generic-crawler-guide#simplified-tree) and
[critical visibility rules](https://developers.google.com/hotels/hotel-prices/structured-data/generic-crawler-guide#critical-visibility-rule)):

- **Strict hierarchy:** Ensure your markup follows the required nesting order (either the simplified tree or the full [structured data reference](https://developers.google.com/hotels/hotel-prices/structured-data/hotel-price-structured-data) specification). Out-of-order or improperly nested elements might be missed by the crawler.
- **Visible price:** `itemprop="price"` directly wraps the visible price number without hidden attributes or `<meta>` tags.
- **Machine-readable stay dates:** `checkinTime` and `checkoutTime` (or alternatively `checkinDate` and `checkoutDate` attributes) contain standard `YYYY-MM-DD` date format (optionally using `content="..."` attributes if needed). If a full time (e.g. `2027-08-21T23:59:59` or similar) is used, the date part `YYYY-MM-DD` in beginning is only extracted.
- **Direct element tagging:** All visible properties (hotel name, stay dates, occupancy) wrap visible page text.