GitHub Actions
For a site whose build runs in GitHub Actions and is uploaded to a host from there (Cloudflare Pages direct upload, GitHub Pages, S3, a server). There is no build hook to make, so you add a small endpoint that starts the workflow. Each publish is then one run of the workflow, usually a minute or two of Actions time.
The example endpoint runs as a Cloudflare Pages Function. Any host that runs a small function (Netlify Functions, Vercel Functions, a Worker) works the same way.
Set it up
Section titled “Set it up”-
A GitHub token for the endpoint. GitHub → your picture → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token.
- Resource owner: the account or organisation that owns the repository.
- Repository access: Only select repositories → the site’s repository.
- Repository permissions → Actions: Read and write. Nothing else (Metadata: read is added by itself).
- Note the expiry date: after it, the endpoint answers 502 and the owner’s card says the rebuild was refused.
-
Two secrets where the endpoint runs. On Cloudflare: Workers & Pages → the project → Settings → Variables and secrets → Add, type Secret, for Production:
GITHUB_DISPATCH_TOKEN= the token.REBUILD_HOOK_SECRET= a long random value, for example fromopenssl rand -hex 32. Keep it for step 5.
-
The feed values in GitHub. The repository → Settings → Secrets and variables → Actions:
- Secrets → New repository secret:
JOOGOOS_FEED_KEY= the key. - Variables → New repository variable:
JOOGOOS_FEED_URL= the feed address.
Add both together. A build with one and not the other should stop with a clear error.
- Secrets → New repository secret:
-
The workflow must accept a manual start and pass both values to the build (below).
-
The hook address, for the owner to paste in Joogoos (Business → SEO → Where they are published → Build hook → Save):
https://<your site>/api/rebuild/<REBUILD_HOOK_SECRET> -
Deploy once (run the workflow by hand): Cloudflare reads new secrets only from the next deployment. Then check:
Terminal window curl -X POST -o /dev/null -w "%{http_code}\n" https://<your site>/api/rebuild/wrong # 404curl -X POST -o /dev/null -w "%{http_code}\n" https://<your site>/api/rebuild/<secret> # 202, and a run starts
The endpoint
Section titled “The endpoint”// functions/api/rebuild/[token].js — a Cloudflare Pages Functionexport async function onRequestPost({ params, env }) { // A wrong address looks like no address at all. if (!env.REBUILD_HOOK_SECRET || params.token !== env.REBUILD_HOOK_SECRET) return new Response(null, { status: 404 }); const res = await fetch('https://api.github.com/repos/OWNER/REPO/actions/workflows/site.yml/dispatches', { method: 'POST', headers: { authorization: `Bearer ${env.GITHUB_DISPATCH_TOKEN}`, accept: 'application/vnd.github+json', 'user-agent': 'blog-rebuild', }, body: JSON.stringify({ ref: 'main' }), }); return new Response(null, { status: res.ok ? 202 : 502 });}Replace OWNER/REPO and site.yml with yours. Joogoos rings at most once per publish, thirty seconds after it, and groups several publishes into one ring. If you want a hard ceiling on runs, count them in the endpoint (for example with the GitHub API’s list of today’s runs) and answer 429 past it.
The workflow
Section titled “The workflow”on: push: branches: [main] workflow_dispatch: # the endpoint starts it
jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: 22 } - run: npm ci - run: npm run build env: JOOGOOS_FEED_URL: ${{ vars.JOOGOOS_FEED_URL }} JOOGOOS_FEED_KEY: ${{ secrets.JOOGOOS_FEED_KEY }} # …then upload, e.g. cloudflare/wrangler-action with `pages deploy dist`The build reads the feed exactly as on Netlify.