After building a family calendar system that aggregates events from multiple sports platforms, I realized we needed one more thing: a single calendar feed that automatically stays up-to-date without any manual work.

The solution? GitHub Actions running a Python script every 6 hours to fetch, merge, and publish 1,200+ family events from 6 different sources into one clean .ics feed.

The Challenge

Our family calendar pulls from TeamSnap, GameChanger, PlayMetrics, and SignUpGenius. It works great in the browser, but what if you want all those events in your phone's native calendar app? Or share a single feed with relatives who just want to subscribe and forget about it?

We needed a unified feed that automatically updates as events change across all platforms.

The Solution: GitHub Actions Automation

I built a Python script that runs automatically on GitHub's servers, fetching calendars from all sources and combining them into a single file. The workflow runs every 6 hours and commits the updated calendar back to the repository, where GitHub Pages serves it publicly.

How It Works

The Python Script

The script uses the icalendar library to parse and merge calendar feeds:

  • Fetches 6 calendar sources (TeamSnap, GameChanger, PlayMetrics, SignUpGenius, local files)
  • Parses each .ics file and extracts events
  • Removes duplicates based on event UIDs
  • Combines everything into a single calendar with 1,200+ events
  • Writes the result to family-calendar-combined.ics

The GitHub Action

The workflow is triggered three ways:

  • Schedule - Runs every 6 hours to pick up calendar changes
  • Push events - Runs when local .ics files are updated
  • Manual trigger - Can be run on-demand from the GitHub UI

Technical Implementation

The entire automation stack:

  • Python 3.11 - Script runtime
  • icalendar library - iCal parsing and generation
  • GitHub Actions - Free CI/CD for public repos
  • GitHub Pages - Static hosting of the combined feed

Setting up write permissions was the only tricky part—GitHub Actions needs explicit contents: write permission to commit the updated calendar file back to the repository.

The Results

Now anyone can subscribe to our family calendar with a single URL:

https://paulsnider.net/family/family-calendar-combined.ics

The feed automatically updates every 6 hours with the latest events from all sources. Add it to your calendar app once, and you're done—new events appear automatically as sports schedules change.

Lessons Learned

  • Free is powerful - GitHub Actions provides unlimited free runs for public repositories
  • Automation compounds - Small scripts running regularly save enormous time
  • CI/CD isn't just for code - Data aggregation workflows benefit from the same automation principles
  • Keep it simple - A Python script and a cron schedule beat complex infrastructure

The Impact

What was previously a manual export-and-share process is now completely automated. Family members can subscribe to the feed once and never think about it again. When sports schedules update, everyone's calendars update automatically within 6 hours.

The combination of the interactive web calendar and the automated feed gives us the best of both worlds: rich filtering in the browser, and simple "set it and forget it" subscriptions for phones and desktop calendar apps.

Subscribe to the combined feed at our family calendar, or check out the code on GitHub.