Alfalfa

Facebook events to Google Calendar in 2026: what actually works

Every guide you find for this is broken, and the reason is simple. Facebook removed the calendar export years ago. Here is the method that still works, for a single event or for a whole page's programme on a schedule.

Updated September 2026.

Short version. There is no export button any more. Get the event data out as structured records, then either import a CSV into Google Calendar once, or write an .ics file to a fixed URL and subscribe to it so the calendar keeps itself up to date. Both paths are below, including the conversion script.

Why the old instructions fail

If you have been sent here by a forum thread, you have probably already tried these:

So anything that promises a one-click sync is either very old or describing a product that quietly stopped working.

Step 1: get the events as data

You need the events as records before a calendar can read them. The Facebook Events Scraper takes a search term, a city, a page URL or a single event URL and returns one record per event. No Facebook account is involved.

The fields that matter for a calendar are these:

FieldWhat it holds
nameEvent title
utcStartDate, utcEndDateStart and end in UTC, ISO 8601. Use these rather than the display strings.
address, location.nameVenue name and one-line address
descriptionEvent description
urlLink back to the event on Facebook
childEventsEvery date of a recurring event, each with its own start and end

Run it once and you have a dataset you can download as JSON, CSV or Excel, or read through the API.

Step 2a: one-off, using Google Calendar's CSV import

Google Calendar accepts a CSV with a fixed set of column names. Export the dataset as CSV, then map the columns like this:

Google Calendar columnValue to use
Subjectname
Start Datedate part of utcStartDate, as MM/DD/YYYY
Start Timetime part of utcStartDate, as hh:mm AM/PM
End Date, End Timesame from utcEndDate
Locationaddress, or location.name when the address is empty
Descriptiondescription, plus the url so you can get back to the event

Then open Google Calendar, go to Settings, choose Import and export, pick the file and the destination calendar. Two things to watch: the times you import are read in the calendar's own time zone, so convert from UTC first if your calendar is not set to UTC, and Google will happily create duplicates if you import the same file twice.

Step 2b: keep a calendar in sync with an .ics feed

This is the version worth setting up if you are a venue, a promoter, or you run a community site. Schedule the scraper, convert each run's output into an .ics file at a stable URL, and subscribe to that URL once. Google refreshes subscribed calendars on its own schedule, usually several times a day.

The script below reads a finished run's dataset straight from the Apify API and writes events.ics. It handles the escaping rules that trip people up, expands recurring events into their individual dates, and skips anything without a start time.

#!/usr/bin/env python3
"""Turn a Facebook Events Scraper dataset into an .ics calendar file."""
import json, urllib.request
from datetime import datetime, timezone

DATASET_URL = "https://api.apify.com/v2/datasets/<DATASET_ID>/items?clean=true&format=json&token=<TOKEN>"

def ics_time(iso):
    # "2026-04-24T22:30:00.000Z" -> "20260424T223000Z"
    return datetime.strptime(iso[:19], "%Y-%m-%dT%H:%M:%S").strftime("%Y%m%dT%H%M%SZ")

def esc(text):
    # commas, semicolons, backslashes and newlines are special in iCalendar
    return (str(text or "").replace("\\", "\\\\").replace(";", "\\;")
            .replace(",", "\\,").replace("\r\n", "\\n").replace("\n", "\\n"))

def fold(line):
    # iCalendar lines must not exceed 75 octets; continuation lines start with a space
    out, raw = [], line.encode("utf-8")
    while len(raw) > 75:
        cut = 75
        while cut > 0 and (raw[cut] & 0xC0) == 0x80:  # never split a UTF-8 character
            cut -= 1
        out.append(raw[:cut].decode("utf-8"))
        raw = b" " + raw[cut:]
    out.append(raw.decode("utf-8"))
    return "\r\n".join(out)

def occurrences(event):
    """One entry per date: recurring events carry every occurrence in childEvents."""
    children = event.get("childEvents") or []
    if children:
        for child in children:
            if child.get("utcStartDate"):
                yield child["utcStartDate"], child.get("utcEndDate"), child.get("id") or event.get("id")
    elif event.get("utcStartDate"):
        yield event["utcStartDate"], event.get("utcEndDate"), event.get("id")

events = json.load(urllib.request.urlopen(DATASET_URL))
stamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
lines = ["BEGIN:VCALENDAR", "VERSION:2.0", "PRODID:-//alfalfa//facebook-events//EN",
         "CALSCALE:GREGORIAN", "METHOD:PUBLISH"]

for event in events:
    place = event.get("address") or (event.get("location") or {}).get("name") or ""
    body = event.get("description") or ""
    if event.get("url"):
        body = (body + "\n\n" + event["url"]).strip()
    for start, end, uid in occurrences(event):
        lines += ["BEGIN:VEVENT",
                  fold("UID:%s@alfalfa.cz" % (uid or start)),
                  "DTSTAMP:" + stamp,
                  "DTSTART:" + ics_time(start)]
        if end:
            lines.append("DTEND:" + ics_time(end))
        lines += [fold("SUMMARY:" + esc(event.get("name"))),
                  fold("LOCATION:" + esc(place)),
                  fold("DESCRIPTION:" + esc(body))]
        if event.get("url"):
            lines.append(fold("URL:" + event["url"]))
        lines.append("END:VEVENT")

lines.append("END:VCALENDAR")
with open("events.ics", "w", encoding="utf-8", newline="") as handle:
    handle.write("\r\n".join(lines) + "\r\n")
print("wrote events.ics with %d events" % len(events))

Put events.ics somewhere with a fixed public address, then in Google Calendar choose Other calendars, From URL, and paste it. Give the file the same name every time you regenerate it, otherwise the subscription breaks.

Details that will bite you

Step 2c: Apple Calendar and iPhone

The same .ics file works on a Mac and an iPhone, so the iPhone question has the same answer. One-off: open events.ics in Apple Calendar (File, Import on a Mac; on an iPhone open the file from Mail or Files and tap Add All). Kept in sync: in Apple Calendar choose File, New Calendar Subscription and paste the file's URL; on an iPhone go to Settings, Calendar, Accounts, Add Account, Other, Add Subscribed Calendar. iCloud then pushes the subscription to every device signed in with the same Apple ID, so the phone updates on its own.

If you would rather not maintain the script above, the same converter is published as a small open-source tool, facebook-events-to-ics: one file, no dependencies, reads a dataset file or the dataset URL and writes the .ics, recurring dates included.

Which one should you use

SituationMethod
You want a handful of events in your own calendar todayCSV import, step 2a
You run a venue, club or festival page and want the programme to stay currentScheduled run plus .ics subscription, step 2b
You live in Apple Calendar or on an iPhoneSame .ics file, step 2c
You publish a what's-on site or newsletterScheduled run, then read the dataset from the API and render it yourself

Questions people ask

Can you still export Facebook events to Google Calendar?

Not with a button on Facebook. The export was removed. You can still get public event data out and convert it, which is what this page describes.

How do I get Facebook events on my iPhone calendar?

Convert the events to an .ics file (step 2b) and either open the file on the phone and tap Add All, or subscribe to its URL under Settings, Calendar, Accounts, Add Subscribed Calendar. Subscribed calendars refresh on their own. Step 2c has the details.

Why did my Facebook calendar feed stop working?

The feed endpoints were retired. An old subscription keeps whatever it already downloaded and never receives anything new, so it looks alive but is frozen.

Does this need a Facebook account?

No. The scraper reads only what Facebook shows a visitor who is not signed in, so there is no account to connect and nothing of yours at risk.

Will it get every event from a page?

It returns the upcoming events a page lists publicly, and past events too if you point it at the past events URL. Events that Facebook hides from signed-out visitors, such as private ones, are not visible to anybody without an invitation.

Try the Facebook Events Scraper See the ready-made example