A Cloudflare Worker that acts as a proxy to forward GitHub webhooks to Matrix rooms with proper formatting and authentication.
- π Transforms GitHub webhook payloads into Matrix-formatted messages
- π Securely adds Matrix authentication token to requests
- π Supports multiple GitHub event types:
- Workflow runs (success/failure/cancelled)
- Pull requests (opened/closed/merged/updated)
- Issues (created/closed/reopened)
- Comments (on issues and PRs)
- Push events
- Releases
- π¨ Beautiful formatting with emojis and HTML styling
- Cloudflare account (free tier works)
- Node.js and npm/yarn installed locally
- Matrix access token for your bot/user
- Domain configured in Cloudflare (optional - can use workers.dev subdomain)
# Install dependencies using npm
npm install
# OR using yarn
yarn installnpx wrangler loginThis will open your browser to authenticate with your Cloudflare account.
Update wrangler.toml with your settings:
-
Set your Matrix room ID:
[vars] MATRIX_ROOM_ID = "!yourRoomId:matrix.org"
- Use the internal room ID (starts with
!) - Not the alias (like
#room:matrix.org) - Find it in Element: Room Settings β Advanced β Internal room ID
- Use the internal room ID (starts with
-
Configure your domain (optional):
- If using a custom domain, update the
patternandzone_namein the routes section - Otherwise, comment out the routes section to use the default workers.dev subdomain
- If using a custom domain, update the
-
Change the worker name (optional):
- Update
namein the toml file (this affects your worker URL)
- Update
The worker uses two secrets that need to be added via Cloudflare's secret management:
Option 1: Use the login script (Recommended)
npm run matrix-loginThis interactive script will:
- Prompt for your Matrix credentials
- Login with refresh_token disabled for stability
- Show you the access token
- Optionally set it in Cloudflare automatically
Option 2: Manual token setup
npx wrangler secret put MATRIX_TOKENWhen prompted, paste your Matrix access token.
Note about token stability:
- Matrix tokens can expire or change when you log in/out
- The login script creates a stable token by disabling refresh tokens
- Keep the "GitHub Webhook Bot" device logged in to maintain token validity
- Consider using a dedicated bot account for maximum stability
npx wrangler secret put GITHUB_WEBHOOK_SECRETWhen prompted, paste a secure secret string. You'll use this same secret when configuring the GitHub webhook.
Generating a secure secret:
# On Linux/Mac:
openssl rand -hex 32
# or
openssl rand -base64 32
# Or use any password generator to create a long random stringImportant: Both secrets are encrypted and stored securely by Cloudflare. Never commit these to your repository.
Important: The authentication token must be from a Matrix user that is already in the room where you want to send messages.
Getting your Matrix token:
-
Create a dedicated Matrix user (recommended):
- Create a new Matrix account specifically for GitHub notifications (e.g.,
@github-bot:matrix.org) - Join this user to your target Matrix room
- Use this user's access token
- Create a new Matrix account specifically for GitHub notifications (e.g.,
-
Get the access token:
- Element: Settings β Help & About β Access Token (at the bottom)
- Other clients: Check their documentation
- Via API: Login and use the access token from the response
-
Ensure the user has permission:
- The user must be in the room you're sending to
- The user must have permission to send messages in that room
# Using npm
npm run deploy
# OR using yarn
yarn deploy- Go to your GitHub repository β Settings β Webhooks
- Click "Add webhook"
- Configure:
- Payload URL:
- Custom domain:
https://your-domain.com/webhook/ - Workers.dev:
https://github-matrix-webhook-proxy.<your-subdomain>.workers.dev/webhook/
- Custom domain:
- Content type:
application/json - Secret: Enter the same secret you used for
GITHUB_WEBHOOK_SECRET - SSL verification: Enable (recommended)
- Events: Choose which events you want to forward:
- Recommended: Issues, Pull requests, Push, Workflow runs
- Or select "Send me everything"
- Payload URL:
- Click "Add webhook"
GitHub will send a ping event to verify the webhook is working.
The worker uses three configuration values:
-
MATRIX_ROOM_ID (in
wrangler.toml):- The Matrix room ID where messages will be sent
- Must use the internal room ID format:
!roomid:matrix.org - Find it in Element: Room Settings β Advanced β Internal room ID
-
MATRIX_TOKEN (added as a secret):
- The access token for the Matrix user
- Added via
wrangler secret put MATRIX_TOKEN - Never commit this to your repository
-
GITHUB_WEBHOOK_SECRET (added as a secret):
- Shared secret for verifying GitHub webhooks
- Added via
wrangler secret put GITHUB_WEBHOOK_SECRET - Use the same value in GitHub webhook settings
If using a custom domain:
- Ensure your domain is added to Cloudflare
- Update
wrangler.toml:[[routes]] pattern = "your-domain.com/webhook/*" zone_name = "your-domain.com"
Test your webhook proxy locally:
# Start local development server
npx wrangler dev
# In another terminal, send a test webhook
curl -X POST http://localhost:8787/webhook/ \
-H "Content-Type: application/json" \
-d '{"action": "opened", "sender": {"login": "testuser"}, "repository": {"full_name": "test/repo"}}'-
401 Unauthorized from Worker
- The GitHub webhook secret doesn't match
- Ensure you used the exact same secret in both GitHub and Cloudflare
- Check that GitHub is sending the
X-Hub-Signature-256header
-
401 Unauthorized from Matrix
- Check your Matrix token is correct
- Ensure the token has permission to post in the room
- Verify the room ID is correct
-
Worker not receiving webhooks
- Check the webhook URL in GitHub settings
- Verify the worker is deployed:
npx wrangler tail - Check GitHub webhook delivery history for errors
-
Messages not formatted correctly
- Check the worker logs:
npx wrangler tail - Verify the GitHub event type is supported
- Check the worker logs:
Monitor your worker logs in real-time:
npx wrangler tailThe worker currently formats these GitHub webhook events:
- Repository Events: Created, deleted, archived, unarchived, publicized, privatized, renamed, transferred
- Workflow Runs: Shows status with emojis (β
success, β failure,
β οΈ cancelled) - Pull Requests: Open, close, merge, synchronize, reopen actions
- Issues: Create, close, reopen, assign, label actions
- Comments: On issues and pull requests with preview text
- Pushes: Number of commits and branch
- Releases: Published, created, edited, deleted
- Branch/Tag Events: Create and delete
- Stars: Star and unstar events
- Forks: Repository fork events
- Labels: Create, edit, delete (filtered for ghost users during repo creation)
Other events will show a generic message with event type information.
- The Matrix token and GitHub webhook secret are stored securely as Cloudflare secrets
- The worker validates all incoming webhooks using HMAC-SHA256 signatures
- Only authenticated GitHub webhooks are forwarded to Matrix
- The worker only accepts POST requests to
/webhook/ - All requests are proxied without storing any data
To modify the worker:
- Edit the TypeScript files in
src/ - Test locally:
npx wrangler dev - Deploy changes:
npm run deploy
src/
βββ index.ts # Main worker entry point
βββ types.ts # TypeScript type definitions
βββ utils.ts # Utility functions (signature verification, etc.)
βββ event-config.ts # Event configuration and templates
βββ event-handlers.ts # Complex event handler functions
βββ formatter.ts # Message formatting logic
npm run deploy- Deploy the worker to Cloudflarenpm run dev- Run the worker locally for testingnpm run tail- View real-time logs from the deployed workernpm run matrix-login- Interactive script to get a stable Matrix token
MIT License - See LICENSE file for details
This repository provides a generic, optional webhook filtering engine. Keep organization-specific policy in a private deployment repository or in Cloudflare environment variables.
Set GITHUB_ORG to reject payloads from other organizations and set
WEBHOOK_FILTER_CONFIG to a versioned JSON object. If the configuration is
missing, immediate webhook delivery remains allow-all for backward
compatibility. Repository inclusion defaults to every repository; exclusions
always win. Rules are evaluated in order and the first match wins.
See config/filter-config.example.json
for the complete configuration shape. Supported rule selectors include event,
action, repository, branch, actor, workflow name, workflow trigger, workflow
conclusion, and commit-message wildcard patterns.