- Event powers Google's event rich result + the dedicated Events search experience. Eligible events appear with date, location, ticket link, and an "Add to calendar" button.
- Required:
name,startDate,location. The recommended floor is much larger:endDate,eventStatus,eventAttendanceMode,image,description,offers,organizer,performer. - Three attendance modes:
OfflineEventAttendanceMode(in-person only),OnlineEventAttendanceMode(virtual only),MixedEventAttendanceMode(hybrid). Always set this - missing it is the single most common breakage. - Hybrid events use an array of locations: one
Placefor the physical venue + oneVirtualLocationfor the stream URL. - Status transitions matter: when canceling, postponing, or moving online, update
eventStatus(EventCancelled/EventPostponed/EventMovedOnline) and leave the original event live. Don't delete the URL.
Chapter 1. Before you start
Event schema unlocks the Event rich result, which historically dominated the Events search experience and surfaces with date, time, venue, ticket link, and a calendar-add button. After the 2020 pandemic-era updates, Google explicitly added robust support for virtual and hybrid events, including the requirement that eventAttendanceMode be set on every event.
- Confirm the page is a single event, not a recurring series or an event listing page. Recurring series use
EventSerieswith childEventobjects. Listings useItemListwrapping individual Events. - Pull
startDatewith timezone offset. "2026-06-15T18:00:00-05:00" beats "2026-06-15T18:00:00" - explicit timezone is required when Google has to display the event time to users in different timezones. - Decide the
eventAttendanceMode. This is non-optional for 2026 best practice: every event is offline, online, or mixed. - Identify the canonical event URL. One URL per event instance. Recurring series should still have a permalink per instance.
eventAttendanceMode, which Google now treats as a hard prerequisite. 12 had no endDate, leaving Google to guess when the event ended. 9 had ticketed events with no offers block. 7 had deleted canceled event pages entirely instead of updating eventStatus to EventCancelled, breaking refund pathways for users who'd already bookmarked the page.
Chapter 2. What does Event schema actually do for SEO + AI search?
Four things, in descending order of importance.
- Event rich result in the SERP. Date, location, ticket link, calendar add. The result is visually distinct - much taller than a standard blue link.
- Google Events search experience inclusion. The dedicated Events tab and the "events near me" Knowledge Panel pull from Event schema.
- "Add to Google Calendar" surface. Eligible events get an add-to-calendar button directly in the SERP. Users save the event without ever opening the page.
- AI engine event answers. ChatGPT, Perplexity, and Gemini cite Event-schema'd pages when answering "what events are happening at X" / "when is Y conference" queries.
Chapter 3. Required and recommended properties
{
"@context": "https://schema.org",
"@type": "Event",
"@id": "https://www.example.com/events/cap-summit-2026#event",
"name": "Capconvert Summit 2026",
"description": "A two-day conference on AI-era SEO and GEO, with workshops, case studies, and a live audit session.",
"image": [
"https://www.example.com/events/cap-summit-2026/hero-1x1.jpg",
"https://www.example.com/events/cap-summit-2026/hero-16x9.jpg"
],
"startDate": "2026-09-15T09:00:00-05:00",
"endDate": "2026-09-16T17:00:00-05:00",
"eventStatus": "https://schema.org/EventScheduled",
"eventAttendanceMode": "https://schema.org/MixedEventAttendanceMode",
"location": [
{
"@type": "Place",
"name": "Capconvert HQ",
"address": {
"@type": "PostalAddress",
"streetAddress": "1234 W Madison St",
"addressLocality": "Chicago",
"addressRegion": "IL",
"postalCode": "60607",
"addressCountry": "US"
}
},
{
"@type": "VirtualLocation",
"url": "https://www.example.com/events/cap-summit-2026/livestream"
}
],
"organizer": { "@id": "https://www.capconvert.com/#organization" },
"performer": [
{ "@type": "Person", "name": "Jacque Bichara" },
{ "@type": "Person", "name": "Speaker Two" }
],
"offers": [
{
"@type": "Offer",
"name": "In-person ticket",
"price": "799",
"priceCurrency": "USD",
"availability": "https://schema.org/InStock",
"validFrom": "2026-04-01T00:00:00-05:00",
"url": "https://www.example.com/events/cap-summit-2026/tickets/in-person"
},
{
"@type": "Offer",
"name": "Virtual ticket",
"price": "199",
"priceCurrency": "USD",
"availability": "https://schema.org/InStock",
"url": "https://www.example.com/events/cap-summit-2026/tickets/virtual"
}
],
"maximumAttendeeCapacity": 300,
"remainingAttendeeCapacity": 84
}
Two enums that earn their place: eventStatus (use EventScheduled for normal events, switch to EventCancelled / EventPostponed / EventMovedOnline when the situation changes) and eventAttendanceMode (which Google now treats as required even though Schema.org marks it optional).
Chapter 4. Location modeling: Place, VirtualLocation, and hybrid
| Event type | location property | eventAttendanceMode |
|---|---|---|
| In-person only | Place with PostalAddress | OfflineEventAttendanceMode |
| Virtual only (webinar, livestream) | VirtualLocation with url | OnlineEventAttendanceMode |
| Hybrid (in-person + livestream) | Array: [Place, VirtualLocation] | MixedEventAttendanceMode |
For VirtualLocation, the url should be the URL of the livestream landing page or the watch URL itself. For VirtualLocation events where the URL isn't public until shortly before the event (e.g., paid webinar), set url to the registration page until the live URL is available.
Recurring events
For a series, use EventSeries as the parent and one Event per instance. Reference the series from each instance via superEvent. Don't ship a single Event with recurring rules - that's not in the Schema.org spec.
Chapter 5. Offers and event status transitions
Offers
Free events: omit offers or include one Offer with price: "0". Multi-tier ticketing: one Offer per tier, distinguished by name and price. Always include availability - users need to know if tickets are still on sale.
Status transitions
When something changes, update eventStatus in place. Do not delete the URL.
// Event canceled - keep page live, refund pathways visible
"eventStatus": "https://schema.org/EventCancelled"
// Event postponed - update startDate to new date OR add "previousStartDate"
"eventStatus": "https://schema.org/EventPostponed",
"startDate": "2026-10-15T09:00:00-05:00",
"previousStartDate": "2026-09-15T09:00:00-05:00"
// Event moved online - keep page, swap location to VirtualLocation
"eventStatus": "https://schema.org/EventMovedOnline",
"eventAttendanceMode": "https://schema.org/OnlineEventAttendanceMode",
"location": { "@type": "VirtualLocation", "url": "..." }
Google specifically introduced EventMovedOnline and previousStartDate during the 2020 pandemic and they remain the canonical way to update a disrupted event.
Chapter 6. Where do you place Event schema on the site?
One Event record per event page, in the <head>. For an events listing page, use ItemList with itemListElement array referencing each individual Event by @id - don't duplicate the full Event records in the listing.
Reference the parent Organization via organizer. For ticketed events sold through a third-party platform (Eventbrite, Ticketmaster), put your URL as url on the Offer and link out to the ticket vendor.
Chapter 7. The breakages we see most often
Ranked by frequency across 22 event-publishing audits:
- No
eventAttendanceMode. Google treats this as effectively required for 2026 events. 16 of 22. - No
endDate. Multi-day events look like single-day events in the rich result. 12 of 22. - Ticketed events with no
offersblock. Users can't see price or "buy" CTA in the SERP. 9 of 22. - Canceled events deleted instead of marked
EventCancelled. Breaks refund discovery for users who'd bookmarked the page. 7 of 22. - Hybrid events with only
Placein location, missing the VirtualLocation. The online attendees show up in person to the wrong venue. 5 of 22. startDatewithout timezone. The rich result displays the wrong local time. 4 of 22.
Tracked on running sites via our Sentry structured-data rule set.
FAQ
Do I need a separate Event record for every instance of a recurring series?
Yes. Each event instance has its own URL and its own Event record. Use EventSeries as the parent and link each instance via superEvent. Don't try to express recurrence as a rule inside a single Event.
What's the difference between EventCancelled and just deleting the page?
EventCancelled keeps the URL live so existing attendees can find refund and rescheduling info. Deleting the URL breaks user pathways and may leave the rich result showing as scheduled until Google recrawls. Always update status; never delete.
How do I model a free event?
Either omit offers entirely or include one Offer with price: "0" and priceCurrency. Google handles both. Including a price-zero Offer makes the "Free" badge appear in the rich result, which slightly lifts CTR.
Can I include performer if it's a non-music event?
Yes. performer covers any speaker, presenter, or featured participant. For conferences with multiple speakers, use an array of Person objects. The performer surface in the rich result helps with named-speaker search queries.
What if my event sells out?
Update availability on the Offer to https://schema.org/SoldOut. The "Sold out" badge replaces the ticket-buy CTA in the rich result. Don't remove the Offer; the price and tier info still help users decide whether to wait-list.
How far in advance should Event schema be live?
As soon as the event is confirmed. Google indexes events months in advance and the rich result accuracy improves with longer lead time. The Indexing API is supported for Event pages and is the canonical way to notify Google of new or changed events.
References
- Schema.org. "Event." schema.org/Event
- Google Search Central. "Event (Event) structured data." developers.google.com/search/docs/appearance/structured-data/event
- Schema.org. "VirtualLocation." schema.org/VirtualLocation
- Schema.org. "EventAttendanceModeEnumeration." schema.org/EventAttendanceModeEnumeration
- Schema.org. "EventStatusType." schema.org/EventStatusType
- Schema.org. "Schema Markup Validator." validator.schema.org