Structured Data Guide

Shopify Booking & Appointment Product Schema: ReserveAction & BookAction for AI Agents

Shopify powers thousands of stores selling bookable services — haircuts, personal training, consultations, photography sessions, car detailing. AI shopping agents answering "book a [service] near me" don't know your listing is bookable unless your structured data says so. potentialAction with BookAction is that signal.

TL;DR Add potentialAction with @type: BookAction to your Service JSON-LD. The target is an EntryPoint with urlTemplate pointing to your booking flow (Shopify product URL or third-party booking app URL). Use ReserveAction for free/no-payment reservations; BookAction for paid appointment bookings. Tag bookable Shopify products with schema-bookable and output the action block conditionally in product.liquid.

Why Booking Schema Matters for AI Agent Discovery

The query "book a [service]" is fundamentally different from "buy a [product]." Shoppers asking to book have high commercial intent and expect to interact with a scheduling flow — not just see a product page. AI agents are increasingly learning to distinguish between:

The potentialAction property on Service declares that this listing has an actionable next step — in this case, a booking flow. AI agents that encounter a BookAction in a service's structured data can:

ReserveAction vs. BookAction: Which to Use

Action Type Use When Payment Examples
ReserveAction Holding or reserving a slot without immediate payment No payment at booking Free consultation, restaurant reservation, trial class, waitlist sign-up
BookAction Purchasing a booking upfront through the booking flow Payment at booking Haircut appointment, personal training session, photography booking, car detailing

Most Shopify bookable services collect payment at checkout (because Shopify's cart and checkout are the payment flow). Use BookAction for these. If you offer free bookings or consultations where no payment is taken when scheduling, use ReserveAction.

Booking Schema Properties Reference

Property On Type Description
potentialAction Service, Product Array of actions the user can take — include BookAction or ReserveAction here
@type Action BookAction or ReserveAction
target Action EntryPoint describing the booking URL
urlTemplate EntryPoint The URL template for the booking flow
inLanguage EntryPoint Language of the booking page ("en")
actionStatus Action PotentialActionStatus (available to take), CompletedActionStatus (booking confirmed)
scheduledTime ReserveAction / BookAction ISO 8601 DateTime for the booked appointment (if known at structured data time)
provider ReserveAction / BookAction Who fulfills the booking (Organization or Person)

BookAction JSON-LD Example: Hair Salon Appointment

{
  "@context": "https://schema.org",
  "@type": "Service",
  "name": "Balayage Color & Style — Full Service",
  "serviceType": "Hair Coloring",
  "description": "Full balayage color service with toner, blow-dry, and style finish. 3–4 hours. Book online and choose your stylist.",
  "provider": {
    "@type": "Organization",
    "name": "Luminary Hair Studio",
    "url": "https://luminary-hair.myshopify.com",
    "telephone": "+1-512-555-0199"
  },
  "areaServed": {
    "@type": "City",
    "name": "Austin",
    "containedInPlace": {"@type": "State", "name": "Texas"}
  },
  "availableChannel": {
    "@type": "ServiceChannel",
    "serviceUrl": "https://luminary-hair.myshopify.com/products/balayage-full-service",
    "serviceLocation": {
      "@type": "Place",
      "name": "Luminary Hair Studio — South Congress",
      "address": {
        "@type": "PostalAddress",
        "streetAddress": "1204 S Congress Ave",
        "addressLocality": "Austin",
        "addressRegion": "TX",
        "postalCode": "78704"
      }
    }
  },
  "offers": {
    "@type": "Offer",
    "price": "245.00",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock",
    "url": "https://luminary-hair.myshopify.com/products/balayage-full-service"
  },
  "potentialAction": {
    "@type": "BookAction",
    "target": {
      "@type": "EntryPoint",
      "urlTemplate": "https://luminary-hair.myshopify.com/products/balayage-full-service",
      "inLanguage": "en"
    },
    "actionStatus": "https://schema.org/PotentialActionStatus",
    "provider": {
      "@type": "Organization",
      "name": "Luminary Hair Studio"
    }
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.9",
    "reviewCount": "87",
    "bestRating": "5"
  }
}

ReserveAction JSON-LD Example: Free Consultation Call

{
  "@context": "https://schema.org",
  "@type": "Service",
  "name": "Free 30-Minute Strategy Consultation",
  "serviceType": "Business Consulting",
  "description": "A free 30-minute video call to audit your Shopify store's AI readiness and identify the top 3 structured data gaps. No payment required. Book via Calendly.",
  "provider": {
    "@type": "Organization",
    "name": "CatalogScan",
    "url": "https://catalogscan.com"
  },
  "areaServed": "Online",
  "availableChannel": {
    "@type": "ServiceChannel",
    "serviceUrl": "https://catalogscan.com/products/free-consultation"
  },
  "offers": {
    "@type": "Offer",
    "price": "0",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock",
    "url": "https://catalogscan.com/products/free-consultation"
  },
  "potentialAction": {
    "@type": "ReserveAction",
    "target": {
      "@type": "EntryPoint",
      "urlTemplate": "https://calendly.com/catalogscan/strategy-call",
      "inLanguage": "en"
    },
    "actionStatus": "https://schema.org/PotentialActionStatus"
  }
}

Shopify Liquid Template: BookAction Implementation

{% comment %} product.liquid — BookAction for bookable service products {% endcomment %}
{% assign is_bookable = false %}
{% if product.tags contains 'schema-bookable' %}
  {% assign is_bookable = true %}
{% endif %}

{% assign booking_url = product.metafields.seo.booking_url.value %}
{% unless booking_url %}
  {% assign booking_url = "https://" | append: shop.domain | append: product.url %}
{% endunless %}

Required metafields for bookable service products

Metafield key Type Example value
seo.booking_urlSingle line text (URL)https://bookapp.example.com/book/haircut (or leave blank to use product URL)
seo.service_typeSingle line text"Hair Coloring" / "Personal Training" / "Photography"
seo.area_servedSingle line text"Austin, Texas" / "Online" / "United States"

Booking Schema for Common Shopify Service Categories

Service Category Action Type urlTemplate Target areaServed
Hair salon, spa, beauty BookAction Sesami / Booksy / Shopify product URL City + State
Personal training, fitness BookAction Gym app / Shopify product URL with variant for session City or "Online"
Photography / videography BookAction Honeybook / HoneyFable / Shopify product URL City + region served
Home services (cleaning, repair) BookAction Housecall Pro / Shopify product URL City + surrounding area
Consulting / strategy call ReserveAction (free) / BookAction (paid) Calendly / Acuity link stored in metafield "Online"
Car detailing / auto service BookAction Shopify product URL or external scheduling app City
Tutoring, coaching BookAction Calendly / Zoom link / Shopify product "Online" or local city

Common Booking Schema Mistakes on Shopify

Mistake Effect Fix
Using Product @type instead of Service for bookable listings potentialAction BookAction is semantically inconsistent on Product; AI agents deprioritize it Use Service @type for all bookable service listings
Missing target EntryPoint on potentialAction Structured data validator error; AI agents can't extract the booking URL Always include target: EntryPoint with urlTemplate on any action
Using external booking URL without storing it in a metafield Hardcoded booking URL breaks if you switch booking apps Store booking URL in seo.booking_url metafield; update the metafield when switching apps
Omitting actionStatus Agents don't know if the booking action is currently available Add actionStatus: https://schema.org/PotentialActionStatus
Using BookAction for a free reservation (no payment) Semantic mismatch; ReserveAction is correct for no-payment holds Switch to ReserveAction when product.price == 0 (auto-detect in Liquid)

CatalogScan Booking Schema Checks

CatalogScan's AI Readiness scan identifies Shopify products that appear to be bookable services (by tag, product_type, or keywords like "session", "appointment", "booking", "consultation") and checks whether they include a potentialAction BookAction or ReserveAction in their structured data. Bookable service products without a booking action receive a booking-signal gap warning. The scan also validates that the target EntryPoint has a non-empty urlTemplate that resolves to a real page.

Related guides: Service product schema for Shopify · Local pickup and BOPIS schema · Store location LocalBusiness schema · Shopify schema markup overview

FAQ

What schema.org types are used for bookable appointments on Shopify?

Use Service @type with a potentialAction containing either BookAction (paid booking) or ReserveAction (free/hold reservation). The BookAction has a target EntryPoint with urlTemplate pointing to your booking flow URL — either the Shopify product URL or an external booking app URL stored in a metafield.

What Shopify booking apps work best with BookAction schema?

Apps that create dedicated product pages per service (Sesami, Cowlendar, BookedUp) work best because each service has a product URL you can add potentialAction to. For external booking apps (Calendly, Acuity), store the booking URL in a seo.booking_url metafield and use it as the urlTemplate in EntryPoint.

How does BookAction schema help AI shopping agents?

BookAction signals to AI agents that this listing has an active booking flow — not just an informational page. Agents use this to surface your service in booking-intent queries ("book a massage near me") and may generate "Book now" deep links directly in AI-generated results. Without BookAction, agents treat your service as a static product page.

What is the difference between ReserveAction and BookAction?

ReserveAction is for holding a slot without immediate payment (free consultation, restaurant reservation). BookAction is for paying-at-booking scenarios. For most Shopify service businesses that collect payment via Shopify checkout, BookAction is correct. Use ReserveAction when product.price == 0 (auto-detect this in Liquid).

How do I implement BookAction in Shopify Liquid?

Tag bookable products with 'schema-bookable'. Store the booking URL in a seo.booking_url metafield (falls back to the product URL if not set). In product.liquid, detect the tag and add a potentialAction block with @type: BookAction (or ReserveAction if price == 0), target: EntryPoint, urlTemplate: the booking URL, and actionStatus: PotentialActionStatus.