Back to articles

Automating Frontend Workflows with custom webhooks in GitHub Actions

Complete Guide to Automated CI/CD Pipelines for Static Sites and Modern Web Apps

May 23, 2025
GitHub Actions workflow for frontend projects
automation
frontend
tutorial
javascript
web development
5 min read

Managing content separately from your website’s codebase can be beneficial for security, organization, and collaboration. In this article, I’ll walk you through how I set up GitHub Actions to automatically pull content from a private repository and rebuild my website whenever changes are made.

Overview

The setup in the example for this tutorial involves:

  • A public repository containing the website code.
  • A private repository containing sensitive content/data. Add this as a submodule to your public repository.
  • GitHub Actions workflow that triggers a workflow in my website’s repository whenever my private content repository is updated.
  • Proper authentication and security measures.

Repository Structure

Main Website Repository (Public)

rishikc.com/
├── .github/workflows/
│   └── deploy.yml
│   └── update-content.yml
├── content-repo/
...

Content Repository (Private)

content-repo/
├── .github/workflows/
│   └── trigger-update.yml
├── articles/
└── assets/
└── etc/
└── etc/

Setting Up Authentication

Create a Personal Access Token

First, you’ll need to create a Personal Access Token (PAT) with appropriate permissions:

  1. Go to GitHub Settings > Developer settings > Personal access tokens.
  2. Click “Generate new token”. (I used fine-grained tokens, but you can use classic tokens if you are comfortable with that option)
  3. Select permissions (for private repository access).
  4. Copy the generated token.

For the setup I have in my GitHub repositories, I used :

  • A token with write access to my public repository. This is used in the workflow for my private content repository so that it can dispatch the event.
  • A token with access to my public and private repository. This is used in the workflow for my public repository for the website so that it can pull in the latest commits from the private repository.
  • A token that has only read access to my website and content repositories. This is used for the build and deployment workflow.

This way, I never have a token with any excess permissions than what is required for that particular workflow. Best practices for the win!

For this tutorial, I assume you are setting up your repositories similarly.

Add Repository Secrets

In your website’s public repository:

  1. Go to Settings > Secrets and variables > Actions.
  2. Add the following secrets:
    • CONTENT_UPDATE_PAT: Your Personal Access Token (or PAT) with access to pull in the latest content from the private repository and push the changes in your public repository.
    • READ_ONLY_PAT: Your Personal Access Token with access to read the content of your website’s public repository to pull the latest changes, build and deploy the website.

In your content’s repository:

  1. Go to Settings > Secrets and variables > Actions.
  2. Add the following secrets:
    • EVENT_TRIGGER_PAT: Your Personal Access Token (or PAT) with access to dispatch an event for the website’s repository to trigger the workflow that will pull in the latest commit from this private repository.

GitHub Actions Workflow

Here’s the foundation of the workflow that pulls content and deploys the site.

Build and Deployment Workflow Setup

First, we set up a build and deployment workflow for our website.

name: Build and Deploy

on:
  # Trigger the workflow every time you push to the `main` branch
  push:
    branches: [ main ]
  # Allows you to run this workflow manually from the Actions tab on GitHub.
  workflow_dispatch:

# Allow this job to clone the repo and create a page deployment
permissions:
  contents: read
  pages: write
  id-token: write

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
 - name: Checkout your repository using git
        uses: actions/checkout@v4
        with:
          submodules: true
          token: ${{ secrets.READ_ONLY_PAT }}
          persist-credentials: false
        
    # Additional build and deploy steps...

Workflow to Pull from Private Repository

Create another workflow in your website’s repository that will be triggered whenever an event is dispatched by the private repository:

name: Update Content Submodule and Trigger Deployment

on:
  repository_dispatch:
    types:
      - content-update

jobs:
  update-content-submodule:
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          submodules: true
          token: ${{ secrets.CONTENT_UPDATE_PAT }}
          persist-credentials: false

      - name: Authorize Git
        run: |
          git config --global user.email "$GITHUB_ACTOR@users.noreply.github.com"
          git config --global user.name "$GITHUB_ACTOR"
          git config --global url."https://${{ secrets.CONTENT_UPDATE_PAT }}@github.com/".insteadOf "https://github.com/"
          
      - name: Update content submodule
        run: |
          git submodule sync
          git submodule update --remote --recursive
          git add content
          git commit -m "[github action] auto update content submodule" || echo "No changes to commit"
          git push origin main

Triggering Builds from Content Repository

Now, we will set up our private repository to dispatch an event that will trigger the workflow in our public repository.

Webhook Setup

To automatically trigger builds when content changes, set up a webhook in your private repository:

# .github/workflows/notify-website.yml in content repository
name: Trigger Main Site Update

on:
  push:
    branches:
      - main
  # Allows you to run this workflow manually from the Actions tab on GitHub.
  workflow_dispatch:

jobs:
  dispatch:
    runs-on: ubuntu-latest
    steps:
      - name: Dispatch update to site
        uses: peter-evans/repository-dispatch@v3
        with:
          token: ${{ secrets.EVENT_TRIGGER_PAT }}
          repository: rishichawda/rishikc.com # <your-account/repo-name>
          event-type: content-update          # same as the value in `repository_dispatch` in the workflow of your public repository

That’s all we need to do. It is that simple!

When your private repository is updated, it dispatches an event that triggers the private submodule update in your public repository. Since our website’s repository has been configured to run the deployment whenever there are any changes in its main branch, the deployment workflow will automatically update our website.

Security Considerations

Principle of Least Privilege

  • Use fine-grained PATs when possible.
  • Limit token scope to only necessary permissions.
  • Regularly rotate access tokens (Do not use the no-expiration option).

Environment Variables

  • Never hardcode sensitive information.
  • Use GitHub Secrets for all authentication tokens.
  • Consider using GitHub’s OIDC for enhanced security.

Troubleshooting Common Issues

Authentication Errors

  • Verify PAT permissions and expiration.
  • Check repository names and owner settings.
  • Ensure secrets are properly configured.

Build Failures

  • Check Node.js version compatibility.
  • Verify content structure and dependencies.
  • Review build logs for specific errors.

Conclusion

This setup provides a robust, automated pipeline for managing content separately from your website code while maintaining security and efficiency. The workflow ensures your site stays updated whenever content changes, providing a seamless experience for content management and deployment.

The key benefits include:

  • Separation of concerns between code and content.
  • Automated deployment pipeline.
  • Enhanced security for sensitive content.
  • Scalable architecture for multiple content sources.

With this foundation, you can extend the workflow to include additional features like content validation, multiple environments, and advanced deployment strategies.

More importantly, have fun automating!

You may also be interested in

React hooks useContext and useReducer implementation replacing Redux for state management

React State Management Without Redux: useContext + useReducer Pattern

May 19, 2019

Learn to manage complex React application state without Redux using useContext and useReducer hooks. Create a scalable, Redux-like state management pattern with zero external dependencies.

Read article
Advanced PWA features showing offline support, push notifications, and background sync capabilities

Advanced PWA Features: Offline Support, Push Notifications & Background Sync

August 15, 2024

Master advanced Progressive Web App development with offline caching, push notifications, and background sync. Complete guide with code examples for building robust, app-like web experiences.

Read article
Scalable React application architecture diagram showing Redux store structure with sagas and services

Scalable React Architecture: Redux, Sagas & Services Pattern

May 11, 2019

Build maintainable React applications with proper Redux architecture. Complete guide to organizing Redux store, sagas, services, and selectors for scalable enterprise React projects with best practices.

Read article
Automated Lighthouse audit dashboard showing CI/CD performance testing pipeline for Progressive Web Apps

Automate Lighthouse Audits for Performance Testing in CI/CD

June 29, 2019

Complete guide to automating Lighthouse audits for Progressive Web Apps. Learn to set up automated performance testing with Mocha and Chai, integrate with CI/CD pipelines, and maintain consistent web performance standards.

Read article
Diagram illustrating React application architecture concepts and directory structures.

Scalable React Application Architecture: Best Practices for Directory Structure

April 11, 2019

Learn how to structure your React applications with a scalable and maintainable architecture. Discover practical directory organization patterns based on real-world experience.

Read article
Core Web Vitals metrics dashboard showing performance optimization results

Core Web Vitals: Real-World Optimization Strategies

January 20, 2025

Master Core Web Vitals optimization for improved SEO and user experience. Learn practical strategies to optimize Largest Contentful Paint, Interaction to Next Paint, and Cumulative Layout Shift with real code examples.

Read article