Data Source
To display events in the Readerboard widget, you need to connect a calendar data source. Link your data source to the Set data source property via the widget's data source picker.
How It Works
The widget expects the connected data source to contain calendar or event data from one of the supported platforms. When data arrives, the widget:
- Searches for events - Recursively scans the data object for an
eventsorbookingsarray (up to 3 levels deep). - Detects the calendar type - Examines the structure of the first event to identify which calendar platform produced the data.
- Normalizes events - Maps platform-specific fields into a standard format (title, owner, organization, room, start/end date and time).
- Applies filters - Removes expired events and/or filters by date range based on the widget's Event Filtering settings.
- Groups and paginates - Organizes events into groups (if configured) and splits them across pages that fit the container height.
No manual selection of the calendar type is needed. The detection is fully automatic.
Supported Data Formats
Each calendar platform provides data in a different structure. Below is a description of each supported format and the key fields used by the widget.
Google Calendar
The data must contain calendarDetails, events, and credentialId at the top level.
The calendarDetails object must include a timeZone string property.
{
"calendarDetails": {
"timeZone": "America/New_York",
"..."
},
"credentialId": "...",
"events": [
{
"title": "Team Meeting",
"organizer": "John Doe",
"location": "Room 101",
"start": { "dateTime": "2026-03-19T09:00:00-04:00" },
"end": { "dateTime": "2026-03-19T10:00:00-04:00" }
}
]
}
Field mapping:
| Normalized Field | Source Field |
|---|---|
| Title | title |
| Owner | organizer |
| Organization | (not mapped) |
| Room | location |
| Start/End | start.dateTime / end.dateTime (ISO 8601) |
Microsoft Calendar
The data must contain calendarDetails, events, and credentialId at the top level.
The calendarDetails.id must be a string longer than 50 characters (distinguishes it from Google Calendar).
{
"calendarDetails": {
"id": "AAMkAGI2TGuLAAA=...",
"..."
},
"credentialId": "...",
"events": [
{
"title": "Project Review",
"organizer": "Jane Smith",
"location": "Conference Room B",
"start": { "dateTime": "2026-03-19T14:00:00" },
"end": { "dateTime": "2026-03-19T15:00:00" }
}
]
}
Field mapping:
| Normalized Field | Source Field |
|---|---|
| Title | title |
| Owner | organizer |
| Organization | (not mapped) |
| Room | location |
| Start/End | start.dateTime / end.dateTime (ISO 8601) |
iCalendar (ICS)
The data must contain an events array where the first event has startTimestamp, summary, and lengthInMin fields.
Note that iCalendar events use pre-formatted startTime and endTime strings alongside UNIX timestamps.
{
"events": [
{
"summary": "Staff Meeting",
"location": "Main Hall",
"startTimestamp": 1742389200000,
"endTimestamp": 1742392800000,
"startTime": "09:00",
"endTime": "10:00",
"lengthInMin": 60,
"attendees": [
{ "name": "Alice Johnson" }
]
}
]
}
Field mapping:
| Normalized Field | Source Field |
|---|---|
| Title | summary |
| Owner | First attendee's name |
| Organization | (not mapped) |
| Room | location |
| Start Date | Derived from startTimestamp |
| End Date | Derived from endTimestamp |
| Start/End Time | startTime / endTime (pre-formatted) |
Nexudus
The data must contain an events array where the first event has coworkerId, resourceName, and from fields.
The events key can also be named bookings - the widget will automatically detect it.
{
"events": [
{
"coworkerId": 12345,
"coworkerFullName": "Bob Wilson",
"resourceName": "Meeting Room A",
"notes": "Client presentation",
"from": "2026-03-19T09:00:00",
"to": "2026-03-19T10:30:00"
}
]
}
Field mapping:
| Normalized Field | Source Field |
|---|---|
| Title | notes (falls back to "Booking") |
| Owner | coworkerFullName |
| Organization | (not mapped) |
| Room | resourceName |
| Start/End | from / to (ISO 8601) |
Dean Evans EMS
The data must contain an events array where the first event has reservationID, bookingDate, and roomDescription fields.
{
"events": [
{
"reservationID": 5001,
"bookingDate": "2026-03-19",
"eventName": "Board Meeting",
"contact": "Sarah Davis",
"groupName": "Executive Team",
"roomDescription": "Boardroom 3rd Floor",
"room": "BR-3F",
"timeEventStart": "2026-03-19T13:00:00",
"timeEventEnd": "2026-03-19T14:30:00"
}
]
}
Field mapping:
| Normalized Field | Source Field |
|---|---|
| Title | eventName |
| Owner | contact |
| Organization | groupName |
| Room | roomDescription (falls back to room) |
| Start/End | timeEventStart / timeEventEnd (ISO 8601) |
Ad Astra
The data must contain an events array where the first event has activityName, activityTypeCode, and campusName fields.
{
"events": [
{
"activityName": "Physics 101",
"activityTypeCode": "CLASS",
"campusName": "Main Campus",
"parentActivityName": "Science Department",
"roomName": "Science Hall 201",
"roomNumber": "SH-201",
"startDateTime": "2026-03-19T08:00:00",
"endDateTime": "2026-03-19T09:15:00"
}
]
}
Field mapping:
| Normalized Field | Source Field |
|---|---|
| Title | activityName |
| Owner | (not mapped) |
| Organization | parentActivityName |
| Room | roomName (falls back to roomNumber) |
| Start/End | startDateTime / endDateTime (ISO 8601) |
Momentus Elite
The data must contain an events array where the first event has eventTypeId, accountId, and venueNames fields.
{
"events": [
{
"name": "Annual Gala",
"eventTypeId": 10,
"accountId": 200,
"accountName": "Charity Foundation",
"createdByName": "Michael Brown",
"roomName": "Grand Ballroom",
"venueNames": "Convention Center",
"startDateTime": "2026-03-19T18:00:00",
"endDateTime": "2026-03-19T23:00:00"
}
]
}
Field mapping:
| Normalized Field | Source Field |
|---|---|
| Title | name |
| Owner | createdByName |
| Organization | accountName |
| Room | roomName |
| Start/End | startDateTime / endDateTime (ISO 8601) |
25Live (CollegeNet)
The data must contain an events array where the first event has reservationId, spaces, and event fields.
{
"events": [
{
"reservationId": 7890,
"spaces": {
"formalName": "Lecture Hall A - 500 Seats",
"spaceName": "Lecture Hall A"
},
"event": {
"eventName": "Guest Lecture",
"eventTitle": "AI in Education",
"organizationName": "Computer Science Dept",
"eventStartDt": "2026-03-19T15:00:00",
"eventEndDt": "2026-03-19T16:30:00"
}
}
]
}
Field mapping:
| Normalized Field | Source Field |
|---|---|
| Title | event.eventName (falls back to event.eventTitle) |
| Owner | (not mapped) |
| Organization | event.organizationName |
| Room | spaces.formalName (falls back to spaces.spaceName) |
| Start/End | event.eventStartDt / event.eventEndDt (ISO 8601) |
Oracle OHIP
The data must contain an events array where the first event has eventId, blockIdList, and hotelId fields.
{
"events": [
{
"eventId": { "id": 301 },
"blockIdList": [{ "id": 50 }],
"hotelId": "HOTEL001",
"eventName": "Corporate Retreat",
"blockName": "Acme Corp Block",
"functionSpaceDetails": {
"description": "Palm Ballroom"
},
"eventStartDateTime": "2026-03-19T08:00:00",
"eventEndDateTime": "2026-03-19T17:00:00"
}
]
}
Field mapping:
| Normalized Field | Source Field |
|---|---|
| Title | eventName (falls back to blockName) |
| Owner | (not mapped) |
| Organization | blockName |
| Room | functionSpaceDetails.description |
| Start/End | eventStartDateTime / eventEndDateTime (ISO 8601) |
Standard Format (Pre-Normalized)
If your data is already in the widget's normalized event format, you can pass it directly. The data must contain an events array where the first event has a title field and at least one of startDate or startTime.
This mapper is used as a fallback - it only activates if none of the platform-specific mappers match the data structure.
{
"events": [
{
"title": "Team Standup",
"owner": "Jane Smith",
"organization": "Engineering",
"room": "Room 101",
"startDate": "2026-03-19",
"startTime": "09:00",
"endDate": "2026-03-19",
"endTime": "09:30"
}
]
}
Field mapping:
| Normalized Field | Source Field |
|---|---|
| Title | title |
| Owner | owner |
| Organization | organization |
| Room | room |
| Start Date/Time | startDate / startTime |
| End Date/Time | endDate / endTime |
All fields are optional except title and at least one of startDate/startTime (required for detection). Missing fields default to empty strings.
Data Discovery
The widget does not require the events array to be at the root level of the data source.
It recursively searches up to 3 levels deep into the data object to find:
- An
eventsproperty containing an array - A
bookingsproperty containing an array (automatically treated as events)
This means your data source can wrap the events inside nested objects, and the widget will still find them.
For example, this structure works:
{
"calendar": {
"metadata": { "..." },
"events": [
{ "..." }
]
}
}
Date and Time Parsing
All date/time values (except iCalendar, which uses pre-formatted strings and UNIX timestamps) are parsed from ISO 8601 datetime strings.
The parser also handles timezone suffixes in square brackets (e.g., 2026-03-19T09:00:00[America/Chicago]).
Dates are normalized to YYYY-MM-DD format and times to HH:MM format in the local timezone of the device running the widget.