Back to Blog
Planner and pens on a table next to a laptop, representing calendar planning and scheduling
Tutorial
July 8, 2026
9 min read

How to Add Google Calendar Events to Your Website (Without the Complexity)

By SimpleCalendarJS Team

SimpleCalendarJS~18 KB gzipped · Zero dependencies · Any framework

You have a Google Calendar with events your users need to see — team meetings, class schedules, community events, office hours. Google's default solution is an iframe embed that looks like it was designed in 2012: fixed-width, unresponsive on mobile, and impossible to style. The alternative — the Google Calendar API — gives you raw event data you can render however you want. The catch is that most tutorials make this harder than it needs to be, pulling in OAuth flows and heavyweight libraries for what should be a simple read operation.

The three ways to show Google Calendar events on a website

Before writing code, understand the options and their trade-offs:

ApproachCustomisationMobile-FriendlyBundle CostSetup Complexity
Google iframe embedNoneNo0 KBCopy-paste
FullCalendar + Google pluginHighYes~43 KB + pluginModerate
Google API + SimpleCalendarJSFullYes~18 KBModerate

The iframe embed works if you don't care about design, branding, or mobile users. You paste a URL into an iframe tag and you're done. But the embed renders at a fixed width, can't match your site's fonts or colours, and shows Google's full chrome including navigation arrows and view switchers you may not want.

FullCalendar has a dedicated @fullcalendar/google-calendar plugin that handles the API call for you. It works, but you're adding ~43 KB of core bundle plus the Google Calendar plugin plus whichever view plugins you need. For a marketing site or blog that just needs to list upcoming events, that's a lot of JavaScript.

The Google API + SimpleCalendarJS approach gives you the most control at the smallest cost. Fetch events from the Google Calendar API yourself, map them into your calendar library's format, and render them. With SimpleCalendarJS at ~18 KB gzipped, the total JavaScript you ship is a fraction of the alternatives.

Setting up the Google Calendar API (read-only, no OAuth)

Most Google Calendar API tutorials immediately introduce OAuth 2.0, consent screens, and token management. You don't need any of that for public calendar data. A simple API key is enough.

Step 1: Create a Google Cloud project

  1. Go to console.cloud.google.com
  2. Create a new project (or select an existing one)
  3. Navigate to APIs & Services > Library
  4. Search for Google Calendar API and enable it

Step 2: Create an API key

  1. Go to APIs & Services > Credentials
  2. Click Create Credentials > API Key
  3. Restrict the key: under API restrictions, select Google Calendar API only
  4. Under Application restrictions, add your website's domain as an HTTP referrer

Step 3: Make your Google Calendar public

  1. Open calendar.google.com
  2. Find your calendar in the left sidebar, click the three dots, then Settings and sharing
  3. Under Access permissions for events, check Make available to public
  4. Copy the Calendar ID from the Integrate calendar section — it looks like your-email@gmail.com or a long string ending in @group.calendar.google.com

That's it. No OAuth consent screen, no client secret, no token refresh logic.

Fetching events from the Google Calendar API

The API returns events as JSON. Here's a standalone fetch function:

const GOOGLE_API_KEY = 'YOUR_API_KEY'; const CALENDAR_ID = 'your-calendar-id@gmail.com'; async function fetchGoogleCalendarEvents(startDate, endDate) { const timeMin = startDate.toISOString(); const timeMax = endDate.toISOString(); const url = new URL( `https://www.googleapis.com/calendar/v3/calendars/${encodeURIComponent( CALENDAR_ID )}/events` ); url.searchParams.set('key', GOOGLE_API_KEY); url.searchParams.set('timeMin', timeMin); url.searchParams.set('timeMax', timeMax); url.searchParams.set('singleEvents', 'true'); url.searchParams.set('orderBy', 'startTime'); url.searchParams.set('maxResults', '100'); const res = await fetch(url); if (!res.ok) throw new Error(`Google Calendar API error: ${res.status}`); const data = await res.json(); return data.items || []; }

This returns an array of event objects with summary, start, end, description, location, and other fields. No OAuth token, no gapi client library, no SDK — just a fetch call with your API key.

Rendering events with SimpleCalendarJS

Now pipe those events into a calendar that matches your site's design:

npm install simple-calendar-js
import SimpleCalendarJs from 'simple-calendar-js'; import 'simple-calendar-js/dist/simple-calendar-js.min.css'; const calendar = new SimpleCalendarJs('#calendar', { defaultView: 'month', locale: 'en-US', fetchEvents: async (start, end) => { const events = await fetchGoogleCalendarEvents(start, end); return events.map((event) => ({ id: event.id, title: event.summary, start: new Date(event.start.dateTime || event.start.date), end: new Date(event.end.dateTime || event.end.date), color: event.colorId ? getColorFromId(event.colorId) : '#3b82f6', })); }, onEventClick: (event) => { // Show event details in a modal, tooltip, or sidebar showEventDetails(event); }, });

The fetchEvents callback fires whenever the user navigates to a new month or week. SimpleCalendarJS passes the visible date range, you fetch only the events for that window, and the calendar renders them. No upfront data dump, no client-side filtering of thousands of events.

Handling all-day vs. timed events

Google Calendar events use start.date for all-day events and start.dateTime for timed events. The code above handles both with the || fallback:

start: new Date(event.start.dateTime || event.start.date),

All-day events set start.date to a date string like "2026-07-08" with no time component. Timed events use start.dateTime with a full ISO timestamp. SimpleCalendarJS handles both formats — all-day events render as banners across the top of the day cell, timed events slot into the time grid.

Why not use the FullCalendar Google Calendar plugin?

FullCalendar's @fullcalendar/google-calendar plugin is a wrapper that calls the same API endpoint you just saw above. It adds convenience — you pass a googleCalendarApiKey and googleCalendarId and it handles the fetch — but that convenience has costs:

FactorFullCalendar + Google PluginSimpleCalendarJS + fetch
Bundle size~43 KB core + ~3 KB plugin + view plugins~18 KB total
DependenciesPreact (bundled since v6)Zero
API key handlingEmbedded in config objectYour code, your rules
Error handlingGeneric FullCalendar error callbackFull control over retry logic
Event transformationFullCalendar's event modelMap directly to your data shape
PricingFree (MIT) / Premium $480+/devFree personal / license req. commercial

The FullCalendar plugin is fine for apps already using FullCalendar. But if you're adding a Google Calendar display to a marketing site, blog, or lightweight dashboard, shipping 43 KB+ of calendar code to render a dozen events is hard to justify. SimpleCalendarJS does the same job at a third of the size.

Caching and quota management

The Google Calendar API allows 1,000,000 requests per day per project for free. That sounds generous, but if your page gets 10,000 daily visitors and each page load triggers a fetch, you're at 10,000 requests before accounting for navigation between months. Add a client-side cache to avoid redundant calls:

const eventCache = new Map(); async function fetchWithCache(start, end) { const cacheKey = `${start.toISOString()}_${end.toISOString()}`; if (eventCache.has(cacheKey)) { return eventCache.get(cacheKey); } const events = await fetchGoogleCalendarEvents(start, end); eventCache.set(cacheKey, events); // Expire cache after 5 minutes setTimeout(() => eventCache.delete(cacheKey), 5 * 60 * 1000); return events; }

For higher-traffic sites, add a server-side proxy that caches Google Calendar responses and serves them to your frontend. This keeps your API key off the client, reduces quota consumption to one request per cache interval regardless of traffic, and lets you add server-side transformations like timezone conversion or event filtering.

Going further: syncing private calendars

If you need to display a private calendar — user-specific events, internal team schedules — you'll need OAuth 2.0. That means:

  1. Setting up an OAuth consent screen in Google Cloud Console
  2. Implementing the authorization code flow on your backend
  3. Storing and refreshing access tokens per user
  4. Handling scope consent (https://www.googleapis.com/auth/calendar.readonly)

This is a significant jump in complexity. Google's OAuth flow requires a verified consent screen for production apps, token refresh handling, and webhook management if you want real-time updates. Developers on the Google Calendar API group regularly report issues with rate limiting when using service accounts for domain-wide delegation, and webhook notifications only tell you something changed — not what changed — so you still need follow-up API calls.

For most public-facing use cases (event listings, class schedules, community calendars), the API key approach is the right answer. Reserve OAuth for apps where users explicitly log in and expect to see their personal calendar data.

Summary

  • The Google Calendar iframe embed is zero-effort but offers no customisation, no mobile responsiveness, and no design control
  • The Google Calendar API lets you fetch events as JSON with just an API key — no OAuth required for public calendars
  • SimpleCalendarJS renders those events in ~18 KB gzipped with a fetchEvents callback that maps directly to the API response
  • FullCalendar's Google Calendar plugin adds convenience but ships ~43 KB+ of JavaScript and bundles Preact as a dependency since v6
  • Cache API responses client-side or server-side to stay within the 1,000,000 daily request quota and reduce page load latency
  • Reserve OAuth for private calendar access — public calendars only need an API key and a Calendar ID

Sources & Further Reading

Research & References

Image Credits

All images free to use under the Pexels License.

Frequently Asked Questions

Can I display Google Calendar events on my website without an iframe?

Yes. The Google Calendar API lets you fetch events as JSON data and render them in any UI you want — a custom calendar component, a list view, or cards. You only need a public calendar and an API key for read-only access.

Do I need OAuth to read public Google Calendar events?

No. Public calendars can be read with just an API key — no OAuth consent screen, no user login. OAuth is only required if you need to access private calendars or write events on behalf of a user.

What is the Google Calendar API quota limit?

The API allows up to 1,000,000 requests per day per project at no cost. Per-minute rate limits also apply. As of May 2026, Google has signalled that overage charges may be introduced later in 2026 with at least 90 days' notice.

Why not just embed Google Calendar with an iframe?

The default iframe embed uses Google's fixed styling, ignores your site's design, is not mobile-responsive, and offers almost no customisation. Fetching events via the API and rendering them in your own calendar gives you full control over design and behaviour.

What JavaScript calendar library works best with Google Calendar events?

Any library that accepts event data as JavaScript objects works. SimpleCalendarJS (~18 KB gzipped) accepts events through a fetchEvents callback, making it straightforward to map Google Calendar API responses directly into the calendar. FullCalendar has a dedicated Google Calendar plugin, but it adds to an already large bundle.

Is the Google Calendar API free to use?

Standard use is currently free within the 1,000,000 daily request quota. Google has announced that exceeding quota limits will incur charges later in 2026, but details and pricing have not been finalised yet.

Add a calendar to your app today

Free for personal projects. $49/year or $199 lifetime per commercial project.