> ## Documentation Index
> Fetch the complete documentation index at: https://buttercms.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Event management system

> Leverage ButterCMS + React for an event management system with listings with dates, locations, and categories.

<Tip>
  The below examples use **React**, but the steps inside the dashboard will be the same for all frameworks.
</Tip>

<Card title="Related blog content: build an event ticketing app with ButterCMS & Quarkus" icon="java" href="https://www.buttercms.com/blog/quarkus-tutorial-event-app">
  Develop a functional ticketing app with Quarkus and ButterCMS - book tickets, receive a confirmation message, and more.
</Card>

## What you'll build

An event management system that includes:

* Event listings with dates, times, and locations
* Category-based organization
* Upcoming/past event filtering
* Event detail pages
* Integration with registration platforms
* Calendar display

## Architecture overview

We'll use a combination of ButterCMS features:

| Component  | ButterCMS Feature | Purpose                                              |
| ---------- | ----------------- | ---------------------------------------------------- |
| Events     | Page Type         | Individual event pages with full details             |
| Categories | Collection        | Organize events by type (Conference, Workshop, etc.) |
| Venues     | Collection        | Reusable location information                        |
| Speakers   | Collection        | Presenter profiles (optional)                        |

## Step 1: Create event categories collection

Create a Collection for event categories:

1. Go to **Content Types** → **Collections**
2. Create "Event Categories" with fields:
   * **Name** (Short Text) - Category name
   * **Slug** (Short Text) - URL-friendly identifier
   * **Color** (Short Text) - Display color (hex code)
   * **Icon** (Media) - Category icon (optional)

Example categories:

* Conference
* Workshop
* Webinar
* Meetup
* Training

## Step 2: Create venues collection

Create a Collection for event venues:

1. Create "Venues" with fields:
   * **Name** (Short Text) - Venue name
   * **Address** (Long Text) - Full address
   * **City** (Short Text) - City name
   * **Country** (Short Text) - Country
   * **Latitude** (Number) - For map display
   * **Longitude** (Number) - For map display
   * **Image** (Media) - Venue photo
   * **Capacity** (Number) - Maximum attendees
   * **Website** (Short Text) - Venue website URL

## Step 3: Create the event Page Type

Create a Page Type for events with these fields:

**Basic information**

* **Title** (Short Text): Event name
* **Description** (WYSIWYG): Full event description
* **Featured Image** (Media): Event banner image
* **Category** (Reference): Link to Event Categories

**Date & time**

* **Start Date** (Date): Event start
* **End Date** (Date): Event end
* **Timezone** (Dropdown): Event timezone

**Location**

* **Event Type** (Dropdown): In-Person, Virtual, Hybrid
* **Venue** (Reference): Link to Venues (for in-person)
* **Virtual Link** (Short Text): Video conference URL (for virtual)

**Registration**

* **Registration URL** (Short Text): External registration link
* **Registration Deadline** (Date): Last day to register
* **Price** (Number): Ticket price (0 for free)
* **Max Attendees** (Number): Capacity limit

**SEO**

* **Meta Title** (Short Text)
* **Meta Description** (Long Text)

## Step 4: Fetch and display events

<Tip>
  ### Speed things up with an SDK

  These code examples use native libraries like `fetch` and `requests` to pull data from the API.

  For your actual implementation, we recommend using one of our many SDKs instead, which come with prebuilt support for the various content type API endpoints, as well as features like timeout, error handling, query parameters, and more.
</Tip>

### Fetch all events

```javascript theme={null}
// Fetch all events
const response = await fetch(
  `https://api.buttercms.com/v2/pages/event/?auth_token=${API_TOKEN}`
);
const events = (await response.json()).data;
```

```python theme={null}
# Python example
from butter_cms import ButterCMS

client = ButterCMS('YOUR_API_KEY')
events = client.pages.list('event')['data']
```

### API response structure

```json theme={null}
{
  "data": [
    {
      "slug": "tech-conference-2024",
      "fields": {
        "title": "Tech Conference 2024",
        "description": "<p>Join us for the biggest tech event...</p>",
        "featured_image": "https://cdn.buttercms.com/...",
        "category": {
          "name": "Conference",
          "slug": "conference",
          "color": "#3B82F6"
        },
        "start_date": "2024-06-15T09:00:00Z",
        "end_date": "2024-06-17T18:00:00Z",
        "timezone": "America/New_York",
        "event_type": "In-Person",
        "venue": {
          "name": "Convention Center",
          "address": "123 Main St",
          "city": "San Francisco",
          "country": "USA"
        },
        "registration_url": "https://eventbrite.com/...",
        "price": 299,
        "max_attendees": 500
      }
    }
  ]
}
```

## Step 5: Filter upcoming vs past events

```javascript theme={null}
function filterEvents(events) {
  const now = new Date();

  const upcoming = events.filter(
    (event) => new Date(event.fields.start_date) > now
  );

  const past = events.filter(
    (event) => new Date(event.fields.end_date) < now
  );

  // Sort upcoming by start date (soonest first)
  upcoming.sort((a, b) =>
    new Date(a.fields.start_date) - new Date(b.fields.start_date)
  );

  // Sort past by start date (most recent first)
  past.sort((a, b) =>
    new Date(b.fields.start_date) - new Date(a.fields.start_date)
  );

  return { upcoming, past };
}
```

## Step 6: Build the events UI

### Event card component

```jsx theme={null}
function EventCard({ event }) {
  const { fields } = event;
  const startDate = new Date(fields.start_date);

  return (
    <div className="event-card">
      <img src={fields.featured_image} alt={fields.title} />

      <div className="event-date">
        <span className="month">
          {startDate.toLocaleDateString('en-US', { month: 'short' })}
        </span>
        <span className="day">{startDate.getDate()}</span>
      </div>

      <div className="event-info">
        <span
          className="category"
          style={{ backgroundColor: fields.category.color }}
        >
          {fields.category.name}
        </span>

        <h3>{fields.title}</h3>

        <div className="meta">
          <span className="time">
            {startDate.toLocaleTimeString('en-US', {
              hour: '2-digit',
              minute: '2-digit'
            })}
          </span>

          {fields.event_type === 'In-Person' && fields.venue && (
            <span className="location">
              {fields.venue.city}, {fields.venue.country}
            </span>
          )}

          {fields.event_type === 'Virtual' && (
            <span className="location">Online Event</span>
          )}
        </div>

        <div className="price">
          {fields.price === 0 ? 'Free' : `$${fields.price}`}
        </div>

        <a href={`/events/${event.slug}`} className="btn">
          Learn More
        </a>
      </div>
    </div>
  );
}
```

### Events list with filtering

```jsx theme={null}
function EventsList({ events }) {
  const [filter, setFilter] = useState('upcoming');
  const [categoryFilter, setCategoryFilter] = useState('all');

  const { upcoming, past } = filterEvents(events);
  const displayEvents = filter === 'upcoming' ? upcoming : past;

  const filtered = categoryFilter === 'all'
    ? displayEvents
    : displayEvents.filter(e => e.fields.category.slug === categoryFilter);

  return (
    <div className="events-page">
      <h1>Events</h1>

      <div className="filters">
        <button
          className={filter === 'upcoming' ? 'active' : ''}
          onClick={() => setFilter('upcoming')}
        >
          Upcoming ({upcoming.length})
        </button>
        <button
          className={filter === 'past' ? 'active' : ''}
          onClick={() => setFilter('past')}
        >
          Past ({past.length})
        </button>
      </div>

      <div className="events-grid">
        {filtered.length === 0 ? (
          <p>No events found</p>
        ) : (
          filtered.map((event) => (
            <EventCard key={event.slug} event={event} />
          ))
        )}
      </div>
    </div>
  );
}
```

## Step 7: Event detail page

```jsx theme={null}
function EventDetailPage({ event }) {
  const { fields } = event;
  const startDate = new Date(fields.start_date);
  const endDate = new Date(fields.end_date);

  return (
    <div className="event-detail">
      <img
        src={fields.featured_image}
        alt={fields.title}
        className="hero-image"
      />

      <div className="event-header">
        <span className="category">{fields.category.name}</span>
        <h1>{fields.title}</h1>
      </div>

      <div className="event-meta">
        <div className="date-time">
          <h3>Date & Time</h3>
          <p>
            {startDate.toLocaleDateString('en-US', {
              weekday: 'long',
              year: 'numeric',
              month: 'long',
              day: 'numeric'
            })}
          </p>
          <p>
            {startDate.toLocaleTimeString('en-US', {
              hour: '2-digit',
              minute: '2-digit'
            })}
            {' - '}
            {endDate.toLocaleTimeString('en-US', {
              hour: '2-digit',
              minute: '2-digit'
            })}
          </p>
          <p className="timezone">{fields.timezone}</p>
        </div>

        {fields.event_type === 'In-Person' && fields.venue && (
          <div className="location">
            <h3>Location</h3>
            <p className="venue-name">{fields.venue.name}</p>
            <p>{fields.venue.address}</p>
            <p>{fields.venue.city}, {fields.venue.country}</p>
            {fields.venue.website && (
              <a href={fields.venue.website} target="_blank">
                Venue Website
              </a>
            )}
          </div>
        )}

        {fields.event_type === 'Virtual' && (
          <div className="virtual-info">
            <h3>Virtual Event</h3>
            <p>This event will be held online</p>
          </div>
        )}
      </div>

      <div className="registration-box">
        <div className="price">
          {fields.price === 0 ? 'Free Event' : `$${fields.price}`}
        </div>
        {fields.max_attendees && (
          <p className="capacity">Limited to {fields.max_attendees} attendees</p>
        )}
        <a
          href={fields.registration_url}
          className="register-btn"
          target="_blank"
        >
          Register Now
        </a>
        {fields.registration_deadline && (
          <p className="deadline">
            Registration closes:{' '}
            {new Date(fields.registration_deadline).toLocaleDateString()}
          </p>
        )}
      </div>

      <div
        className="description"
        dangerouslySetInnerHTML={{ __html: fields.description }}
      />
    </div>
  );
}
```

## Integration with external services

<Note>
  Third-party service UIs and embed formats may change. Verify current implementation details on each provider's documentation.
</Note>

### Eventbrite integration

Store Eventbrite event IDs and use their embed widgets:

```jsx theme={null}
function EventbriteWidget({ eventbriteId }) {
  return (
    <div
      id={`eventbrite-widget-${eventbriteId}`}
      dangerouslySetInnerHTML={{
        __html: `<iframe src="https://www.eventbrite.com/tickets-external?eid=${eventbriteId}" height="500" width="100%" frameborder="0"></iframe>`
      }}
    />
  );
}
```

### Google Calendar integration

Generate "Add to Calendar" links:

```javascript theme={null}
function generateGoogleCalendarLink(event) {
  const { fields } = event;
  const start = new Date(fields.start_date).toISOString().replace(/[-:]/g, '').split('.')[0] + 'Z';
  const end = new Date(fields.end_date).toISOString().replace(/[-:]/g, '').split('.')[0] + 'Z';

  const params = new URLSearchParams({
    action: 'TEMPLATE',
    text: fields.title,
    dates: `${start}/${end}`,
    details: fields.description.replace(/<[^>]*>/g, ''),
    location: fields.venue ? `${fields.venue.name}, ${fields.venue.address}` : 'Online',
  });

  return `https://calendar.google.com/calendar/render?${params}`;
}
```

## Scheduled publishing

Use ButterCMS's scheduled publishing to automatically publish events at the right time and unpublish them after they've ended.

<Tip>
  Set up webhooks to trigger notifications when events are published or updated.
</Tip>
