Low to No Cost Solutions

Hosting a Full Analytics Site for $0 with GitHub Pages

6 min read
Hosting a Full Analytics Site for $0 with GitHub Pages

Hosting a real, data-driven website doesn't have to come with a monthly bill. The GH Film Review Pipeline—a football player-evaluation site full of dashboards, snapshots, and season-long reports—runs entirely on GitHub Pages for $0. No VPS, no managed host, no database server. Just a static site published straight from a GitHub Actions workflow.

This post breaks down exactly how that works, and why GitHub Pages is one of my favorite low-to-no-cost hosting solutions.

The Problem I'm Solving

I wanted a public, always-on site for the film review reports without:

  • Paying for a server or managed hosting plan
  • Maintaining and patching infrastructure
  • Wiring up a database for what is really just rendered HTML
  • Worrying about uptime or scaling for traffic spikes

The output of the pipeline is already a folder of static HTML dashboards, PDFs, and CSVs. So the real question wasn't "where do I host an app?"—it was "how do I publish a static folder for free and keep it updated automatically?"

GitHub Pages answers both.

Why GitHub Pages

GitHub Pages serves static files directly from a branch of your repository, on GitHub's infrastructure, at no cost:

  • Free hosting for public repositories, with a generous bandwidth allowance
  • Free HTTPS and a *.github.io domain out of the box (custom domains supported too)
  • Global CDN so the site is fast everywhere
  • Zero servers to manage—nothing to patch, restart, or pay for
  • Git-native deploys—publishing is just a branch push

The one constraint: it only serves static content. For this project, that's a perfect fit—the pipeline produces HTML, so there's nothing dynamic to run at request time.

The Technology Stack

Site output:  Static HTML, CSS, PDFs, CSV (generated by Python)
Build/CI:     GitHub Actions
Hosting:      GitHub Pages (gh-pages branch)
Deploy tool:  peaceiris/actions-gh-pages
Analytics:    Google Analytics 4 (injected at build time)
Cost:         $0

How the Deploy Works

The whole thing is driven by a single GitHub Actions workflow that runs on every push to main. The flow is:

Push to main → Build HTML from CSV outputs → Publish out/ to gh-pages → GitHub Pages serves it

Step 1: Trigger on push

The workflow runs automatically on every push to main, and can also be kicked off manually:

on:
  push:
    branches: [ main ]
  workflow_dispatch:

Step 2: Render the site in CI

Instead of committing generated HTML, the workflow regenerates the dashboards and snapshots from the existing CSV outputs using the project's Python tooling. This is also where I inject the Google Analytics measurement ID from a repository secret—so the analytics ID never lives in the repo:

- name: Setup Python
  uses: actions/setup-python@v5
  with:
    python-version: '3.x'

- name: Install dependencies for HTML generation
  run: |
    python -m pip install --upgrade pip
    pip install pandas

- name: Inject GA and re-render HTML from existing outputs
  env:
    GA_MEASUREMENT_ID: ${{ secrets.GA_MEASUREMENT_ID }}
  run: |
    # ...iterate seasons/weeks, regenerate dashboards,
    # snapshots, season views, and the site index...

The script walks each season directory, rebuilds the weekly dashboards and snapshot pages, generates season-long dashboards, and finally builds a root season selector—so the published site is always in sync with the latest data.

Step 3: Publish to the gh-pages branch

The generated out/ directory is pushed to a dedicated gh-pages branch using the peaceiris/actions-gh-pages action. GitHub Pages is configured to serve from that branch:

- name: Deploy to GitHub Pages (publish out/ to gh-pages)
  uses: peaceiris/actions-gh-pages@v3
  with:
    github_token: ${{ secrets.GITHUB_TOKEN }}
    publish_dir: ./out
    publish_branch: gh-pages
    force_orphan: true

A couple of details worth calling out:

  • github_token: ${{ secrets.GITHUB_TOKEN }} uses the automatically provided token—no personal access token or extra secret to manage.
  • force_orphan: true keeps the gh-pages branch clean by replacing its history each deploy, so the published branch never bloats with old build artifacts.

Step 4: GitHub Pages serves it

Once the gh-pages branch updates, GitHub Pages picks it up and serves the site over HTTPS on the CDN. The result is a fast, public site that costs nothing and updates itself whenever I push new data.

The Permissions Detail That Trips People Up

For the workflow to publish to a branch and to Pages, it needs the right permissions in the job:

permissions:
  contents: write
  pages: write
  id-token: write

If you see the deploy fail with a permissions error, this block (plus the repository's Settings → Actions → Workflow permissions set to read/write) is almost always the fix.

Human Reflections

What I love about this setup is how little of it is actually "hosting." There's no server in the picture at all—just a build step and a branch push. The site has been live and maintenance-free since I set it up, and my hosting bill for it is exactly zero.

The mental shift that made this click for me: stop thinking of the site as an application that needs to run somewhere, and start thinking of it as artifacts that need to be published. Once the output is static, the hosting problem basically disappears.

The only real tradeoff is that everything has to be static. But for content like reports and dashboards, that's not a limitation—it's an advantage. Static sites are faster, safer, and cheaper than anything I could stand up on a server.

When This Approach Works (and When It Doesn't)

GitHub Pages is a great fit when:

  • Your output is static (HTML/CSS/JS, PDFs, images, data files)
  • The repo is public (free tier) or you have Pages enabled on a paid plan
  • You're fine with build-time rendering rather than per-request rendering

Reach for something else when you need:

  • Server-side logic or a database at request time
  • Private, authenticated content
  • Server-rendered pages that change per user

For those, I lean on other low-cost options—but for a publish-and-forget analytics site, GitHub Pages is hard to beat.

What's Next

This is part of my Low to No Cost Solutions series, where I document practical ways to ship real projects without the recurring bills. GitHub Pages + GitHub Actions is one of the highest-leverage combos I've found: free hosting, free CI, automatic HTTPS, and deploys that happen on every push.

If you've got a static site sitting on a paid host, try moving it to Pages—you might be surprised how much you can run for $0.

Have you used GitHub Pages for something beyond a simple landing page? I'd love to hear what you've shipped on it.