Event schema is one of the structured data types with a direct, measurable payoff: get it right and your event can appear in Google’s dedicated event experience with the date, venue, and ticket link displayed before a user even lands on your site. Get it wrong — particularly around location or the online attendance flag — and it either fails validation or gets ignored by the rich results system entirely. I have reviewed enough event markup across client sites to know that the attendance mode property trips people up more than almost anything else in this spec.

What it does

The Event type describes a scheduled occurrence: its name, when it starts and ends, where it takes place (physically or virtually), how people can attend, and whether tickets or registration are available. Google uses this data to populate its event carousels and the event tab in search results. One important constraint: the markup must reflect content that is actually present on the page. If the event date, venue, or ticket details are not visible to a user reading the page, you should not include them in the structured data. This is a rule Google enforces across all schema types, but it comes up often with events because promotional pages are sometimes sparse on specifics.

Key properties

  • name — the event title as it appears on the page.
  • startDate — the start date and time in ISO 8601 format, including timezone offset.
  • endDate — the end date and time; strongly recommended.
  • location — for in-person events, a Place with a full PostalAddress; for online events, a VirtualLocation with a url.
  • eventAttendanceMode — one of three enum values: OfflineEventAttendanceMode, OnlineEventAttendanceMode, or MixedEventAttendanceMode. Must use the full schema.org URL form.
  • eventStatus — one of four enum values from Schema.org: EventScheduled, EventCancelled, EventPostponed, or EventRescheduled. Include this on every event page; it matters most when plans change.
  • offers — a nested Offer with url for tickets, price, priceCurrency, and availability.
  • performer — a Person or PerformingGroup; relevant for concerts, keynotes, or speaker-driven events.

Example: online-only event

{
  '@context': 'https://schema.org',
  '@type': 'Event',
  'name': 'Schema Markup Workshop: Practical Structured Data for SEOs',
  'startDate': '2026-09-15T10:00:00-07:00',
  'endDate': '2026-09-15T13:00:00-07:00',
  'eventStatus': 'https://schema.org/EventScheduled',
  'eventAttendanceMode': 'https://schema.org/OnlineEventAttendanceMode',
  'location': {
    '@type': 'VirtualLocation',
    'url': 'https://terrysamuels.com/events/schema-workshop/'
  },
  'performer': {
    '@type': 'Person',
    'name': 'Terry Samuels'
  },
  'offers': {
    '@type': 'Offer',
    'url': 'https://terrysamuels.com/events/schema-workshop/register/',
    'price': '0',
    'priceCurrency': 'USD',
    'availability': 'https://schema.org/InStock'
  }
}

Hybrid events: MixedEventAttendanceMode

When an event has both in-person and online attendees — a conference with a live stream, for example — the correct value is MixedEventAttendanceMode, and you need to supply both a Place and a VirtualLocation under location. Many implementations get this wrong by picking one or the other. Here is what the full block looks like:

{
  '@context': 'https://schema.org',
  '@type': 'Event',
  'name': 'Structured Data Summit 2026',
  'startDate': '2026-10-22T09:00:00-07:00',
  'endDate': '2026-10-22T17:00:00-07:00',
  'eventStatus': 'https://schema.org/EventScheduled',
  'eventAttendanceMode': 'https://schema.org/MixedEventAttendanceMode',
  'location': [
    {
      '@type': 'Place',
      'name': 'Phoenix Convention Center',
      'address': {
        '@type': 'PostalAddress',
        'streetAddress': '100 N 3rd St',
        'addressLocality': 'Phoenix',
        'addressRegion': 'AZ',
        'postalCode': '85004',
        'addressCountry': 'US'
      }
    },
    {
      '@type': 'VirtualLocation',
      'url': 'https://terrysamuels.com/events/summit-stream/'
    }
  ]
}

Note that location is an array here. Google accepts this pattern and will use the appropriate location node depending on the user’s context in search results.

Managing eventStatus when plans change

The eventStatus property is underused and genuinely useful. Include it on every event page from the start — set it to https://schema.org/EventScheduled — so that if you need to update it later you just change one value rather than retrofitting the whole block. If an event is cancelled, switch to EventCancelled. Google will surface the cancellation status in its event rich results, which saves you from attendees showing up to something that no longer exists. For postponed or rescheduled events, use EventPostponed or EventRescheduled and update startDate accordingly. When an event is rescheduled, the Schema.org spec also lets you use previousStartDate to record what the original date was, which is useful for disambiguation if the event is widely searched under both dates.

Adding event schema to WordPress

If you use The Events Calendar plugin, it outputs some Event structured data automatically — but as of mid-2026 it does not always include eventStatus, eventAttendanceMode, or properly formatted VirtualLocation nodes for online events. I typically add a supplementary JSON-LD block via WPCode targeting the event post type to fill those gaps, rather than trying to filter The Events Calendar’s output directly.

For sites that do not use The Events Calendar, a WPCode snippet that hooks into wp_head and fires only on event pages (identified by post type or slug) gives you full control. Keep your JSON-LD separate from any plugin’s output so you do not create duplicate Event blocks — two Event blocks on the same page is a common cause of rich result failures that can be hard to diagnose.

AI Overviews increasingly surface event information directly in search. When Google’s systems pull event details into an AI-generated answer, they are relying on structured data as the machine-readable signal about the event. A complete Event block with correct attendance mode, a valid offers node, and a properly formatted date is what gets your event details into those surfaces accurately.

How AI Overviews surface event information

AI-generated answers in Google search are increasingly pulling event details directly from structured data rather than parsing prose. When a user searches for an upcoming workshop, conference, or community event, Google’s AI Overview may surface the event name, date, and registration link as a formatted answer block — not a traditional blue link. The source for those details is the Event JSON-LD on the page. If your startDate is missing a timezone offset, the AI-surfaced time may display incorrectly. If your offers block omits url, there may be no registration link in the answer. The structured data is the machine-readable contract between your page and the systems that decide what to surface. Getting it right is not just about rich result carousels — it is about accuracy in every surface where Google synthesizes answers from your content.

One practical implication: keep your event pages live after the event for archive and SEO value, but update eventStatus to EventScheduled for the next occurrence if it is a recurring event, or remove the Event JSON-LD block entirely if the event is a one-time occurrence that has passed. An AI system surfacing an event from a page where the date has already passed is a poor user experience, and it can cause Google to lower its confidence in your structured data quality over time.

Common mistakes

  • Using a bare string for eventAttendanceMode instead of the full schema.org enum URL. Writing OnlineEventAttendanceMode instead of https://schema.org/OnlineEventAttendanceMode is a validation error.
  • Omitting location for online events. Virtual events still require a VirtualLocation node — leaving location out entirely fails Google’s requirements.
  • Not including a timezone offset in startDate. A bare date like 2026-09-15 is technically valid but loses precision; include the time and offset whenever possible.
  • Leaving event markup live after an event has passed without updating or removing the page. Expired event markup does not actively hurt anything, but it clutters validation reports and can confuse audits.
  • Not setting eventStatus on the initial implementation, then scrambling to add it when the event is cancelled or rescheduled.

Event schema is worth getting right the first time because errors here tend to surface prominently in the Rich Results Test. If you want a systematic check of your event pages — or any other structured data — a schema audit will cover it. You can also read about how to test schema markup if you prefer to work through validation yourself, or reach out about schema markup consulting if you are setting up event markup at scale.