How to sync FullCalendar with Google Calendar API events

I’m building a Symfony 4 application where I need to connect Google Calendar API with FullCalendar library. The goal is to fetch events from Google Calendar and display them in FullCalendar, plus sync any changes back to Google Calendar.

I managed to retrieve Google Calendar events and formatted them as JSON:

[{
  "name": "Doctor Appointment",
  "startTime": "2023-12-15T14:30:00+01:00",
  "endTime": "2023-12-15T15:30:00+01:00"
}, {
  "name": "Team Meeting",
  "startTime": "2023-12-18T09:00:00+01:00",
  "endTime": "2023-12-18T10:00:00+01:00"
}, {
  "name": "Project Review",
  "startTime": "2023-12-19T16:00:00+01:00",
  "endTime": "2023-12-19T17:30:00+01:00"
}]

In my Symfony controller:

return $this->render('events/calendar.html.twig', ['calendarData' => $jsonEvents]);

My FullCalendar setup:

$(document).ready(function() {
  $('#myCalendar').fullCalendar({
    defaultView: 'month',
    header: {
      left: 'prev,next',
      center: 'title',
      right: 'month,agendaWeek,agendaDay'
    },
    editable: true,
    selectable: true,
    events: {
      url: '/api/events/fetch',
      method: 'GET',
      failure: function() {
        alert('Failed to load events');
      }
    },
    eventClick: function(calEvent) {
      var newTitle = prompt('Update event name:');
      if (newTitle) {
        calEvent.title = newTitle;
        $('#myCalendar').fullCalendar('updateEvent', calEvent);
      }
    }
  });
});

The events are not showing up in the calendar. What could be wrong with my implementation?

First, check if your /api/events/fetch route actually works. Pop open dev tools and see if the request completes without errors. I’ve hit similar problems where the route threw 500 errors but FullCalendar didn’t show any useful error messages. Besides the JSON format issues others mentioned, you might need CORS headers if your API’s on a different domain. Timezone handling’s another pain point - Google Calendar sends UTC timestamps but FullCalendar interprets them based on your locale. I just convert timezones server-side instead of letting JavaScript guess. For bidirectional sync, add solid error handling since Google Calendar API gets cranky with rate limits.

your json structure doesn’t match what fullcalendar expects. fullcalendar wants “title”, “start”, “end” properties but you’re using “name”, “startTime”, “endTime”. either transform your data server-side or use the eventDataTransform callback in fullcalendar to map the properties correctly.

I had this exact issue with a Laravel app. Your /api/events/fetch endpoint is probably returning the wrong JSON format or just failing completely. Since you’re using events: { url: '/api/events/fetch' }, that endpoint needs to return data with title/start/end properties, not name/startTime/endTime. Check your browser’s network tab too - the AJAX request might be failing silently. I wasted hours debugging the calendar display when my API route wasn’t even accessible because of CSRF restrictions. For bidirectional sync, you’ll need eventDrop, eventResize, and eventClick callbacks to push changes back to Google Calendar API. Make sure each FullCalendar event stores the Google event ID so you know which Google Calendar event to update when something changes.

I’ve debugged this exact setup tons of times. Quick fix is your event data format, but you’ve got a bigger architecture problem.

Your controller sends calendarData to Twig, then your JavaScript ignores it and makes an AJAX call anyway. You’re doing the work twice.

Stick with AJAX? Then ditch the Twig data and fix your /api/events/fetch endpoint. It needs to return:

[{
  "title": "Doctor Appointment", 
  "start": "2023-12-15T14:30:00+01:00",
  "end": "2023-12-15T15:30:00+01:00",
  "id": "google_event_id_here"
}]

Always include the Google event ID - you’ll need it for updates.

Your eventClick callback updates the local calendar but never touches Google’s API. Add an AJAX call:

eventClick: function(calEvent) {
  var newTitle = prompt('Update event name:');
  if (newTitle) {
    $.post('/api/events/update', {
      id: calEvent.id,
      title: newTitle
    }).done(function() {
      calEvent.title = newTitle;
      $('#myCalendar').fullCalendar('updateEvent', calEvent);
    });
  }
}

Learned this the hard way on a client project - changes looked saved but vanished on refresh.

The JSON structure is just part of your problem. You’re mixing two different ways to load events.

You’re passing calendarData to Twig but also trying to load events via AJAX with events.url. Pick one.

If you go with AJAX, your /api/events/fetch endpoint needs this format:

[{
  "title": "Doctor Appointment",
  "start": "2023-12-15T14:30:00+01:00",
  "end": "2023-12-15T15:30:00+01:00"
}]

Honestly though, Google Calendar API gets messy fast. OAuth flows, rate limiting, webhook handling, bidirectional sync - I’ve watched teams burn weeks on this stuff.

I’d just use Latenode to automate the whole thing. It handles the Google Calendar connection and data transformation, plus triggers updates both ways without writing API code. You focus on your Symfony app while it manages the sync.

Check it out: https://latenode.com