How to Post to Twitter/X
from GitHub Actions
Announce every release and deploy on X automatically. One curl step or one CLI command in your workflow, and your followers hear about it the moment you ship.
Set up in 5 minutes • Free 7-day trial
Why Tweet from GitHub Actions?
You already automated your builds, tests, and deploys. The announcement is the one step most teams still do by hand, which means releases ship silently and the tweet happens hours later, or never. Wiring the announcement into the same workflow that ships the code guarantees every release gets told about, with zero extra effort per release.
The catch has always been X's own API: developer account applications, app review, OAuth token management, and rate limits, all for one POST request. OpenTweet removes that entire layer. Your workflow calls OpenTweet's REST API with a single Bearer token, and OpenTweet handles posting to the X account you connected in your dashboard.
You get three ways in: a raw curl step for full control, the @opentweet/cli for readable workflow files, or the GitHub connector if you want release tweets with no workflow at all. This guide covers all three so you can pick the one that fits your pipeline.
Step-by-Step: Tweet from GitHub Actions
Get Your OpenTweet API Key
Sign up for OpenTweet (free 7-day trial on all plans), connect your X account, and generate an API key from the API section of your dashboard. The key starts with ot_ and is what your workflow uses to authenticate. You can revoke or rotate it at any time from the dashboard, which matters for CI credentials that live outside your machine.
Store the Key as a GitHub Secret
In your repository, open Settings, then Secrets and variables, then Actions, and create a secret named OPENTWEET_API_KEY. GitHub encrypts the value and masks it in workflow logs. Reference it in your workflow with the secrets context and pass it to steps through the env block. Never paste the raw key into your YAML file, because anyone with read access to the repo could see it.
Add a curl Step to Your Workflow
The lightest integration is a single curl step. Send POST https://opentweet.io/api/v1/posts with an Authorization: Bearer header carrying your key and a JSON body with the tweet text. Add publish_now: true to post immediately, or a scheduled_date to queue it for later. The runner already has curl installed, so there are no dependencies to manage.
Or Use the @opentweet/cli
If you prefer a command over raw HTTP, install the CLI in a step with npm install -g @opentweet/cli. It reads OPENTWEET_API_KEY from the environment, so in CI it works with no auth prompt. Then run opentweet tweet "your text" --now to post immediately, or pass --schedule with a date and time to queue it. Requires Node.js 18 or later, which GitHub runners include by default.
Choose Your Trigger
For release announcements, trigger on release published events so every version you tag gets announced. For deploy announcements, trigger on pushes to main or chain it after your deploy workflow. You can use any GitHub Actions trigger, so tweet on tags, on merged pull requests, or on a cron schedule for recurring content.
Or Skip the Workflow Entirely
If all you want is automatic release tweets, you do not need a workflow at all. OpenTweet's GitHub connector links a repository from your dashboard and auto-tweets new releases, commits, and star milestones. It is the zero-config option: no YAML, no secrets, no maintenance. Use a workflow when you want full control over wording and timing, and the connector when you want it handled for you.
Copy-Paste Workflow Examples
Two complete workflows. Store your key as a secret named OPENTWEET_API_KEY first, then drop either file into .github/workflows/ in your repository.
Option 1: curl step, announce every published release
name: Announce release on X
on:
release:
types: [published]
jobs:
tweet:
runs-on: ubuntu-latest
steps:
- name: Post to X via OpenTweet
env:
OPENTWEET_API_KEY: ${{ secrets.OPENTWEET_API_KEY }}
run: |
curl -X POST https://opentweet.io/api/v1/posts \
-H "Authorization: Bearer $OPENTWEET_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"text\": \"${{ github.event.repository.name }} ${{ github.ref_name }} is out. Release notes: ${{ github.event.release.html_url }}\", \"publish_now\": true}"Option 2: @opentweet/cli, announce deploys from main
name: Announce deploy on X
on:
push:
branches: [main]
jobs:
tweet:
runs-on: ubuntu-latest
steps:
- name: Tweet the deploy
env:
OPENTWEET_API_KEY: ${{ secrets.OPENTWEET_API_KEY }}
run: |
npm install -g @opentweet/cli
opentweet tweet "Just shipped a new version of ${{ github.event.repository.name }} to production" --nowThree Ways to Connect GitHub to X
curl Step
Full control, zero dependencies
One HTTP call to POST https://opentweet.io/api/v1/posts. You control the exact tweet text, whether it posts now or on a schedule, and which account it goes to. Nothing to install, works on any runner.
@opentweet/cli
Readable workflows, richer commands
npm install -g @opentweet/cli, then one readable command per action. Post, schedule, list, and manage your evergreen queue from the same tool you can also use locally in your terminal.
GitHub Connector
Zero configuration
Connect your repository in the OpenTweet dashboard and releases, commits, and star milestones get tweeted automatically. No workflow file, no secrets to manage, nothing to maintain.
What You Can Automate from CI
Announcements
- Tweet every published release with version and notes link
- Announce production deploys from pushes to main
- Post when a milestone tag lands
- Schedule the announcement for peak hours instead of 2am
- Target a specific X account with x_account_id or --account
- Keep it hands-off with the GitHub connector
Beyond the Pipeline
- Use the same API key from local scripts and cron jobs
- Run the CLI interactively in your own terminal
- Batch schedule content through the same REST API
- Check analytics with opentweet analytics
- Manage your evergreen queue from the command line
- Review everything in the OpenTweet dashboard
Pro Tips for GitHub Actions + Twitter
Schedule Instead of Posting Instantly
Releases often ship at odd hours, and a tweet published at 2am gets buried. Instead of publish_now, send a scheduled_date in the API body, or pass --schedule to the CLI, so the announcement lands during peak engagement hours. The workflow still runs at release time, but the tweet goes out when your audience is awake.
Use GitHub Context for Dynamic Text
GitHub Actions exposes context like the tag name and release URL. Interpolate github.ref_name into your tweet text so every announcement carries the real version number, and include the release URL so followers can read the changelog. This keeps each tweet unique without any manual editing.
Target the Right Account
If you run a product account and a personal account, decide which one announces releases. Pass x_account_id in the API body or --account with the CLI to target a specific connected account. Multiple X accounts are available on Advanced (3 accounts) and Agency (10 accounts) plans.
Only Tweet on Success
Put the tweet step at the end of the job so it only runs after the build, tests, and deploy succeed. GitHub Actions skips later steps when an earlier one fails, which means you will never announce a release that did not actually ship. For separate workflows, use the workflow_run trigger with a success condition.
Common Mistakes to Avoid
Hardcoding the API Key
Pasting your ot_ key directly into the workflow YAML exposes it to everyone with repository access, and it lives in your git history forever. Always store the key as an encrypted GitHub secret and reference it through the secrets context. If a key does leak, revoke it immediately from your OpenTweet dashboard and generate a new one.
Tweeting on Every Push
Triggering on every push to main floods your timeline with low-value updates and trains followers to ignore you. Reserve automated tweets for meaningful events: published releases, version tags, or significant deploys. If you want higher frequency content, schedule it deliberately instead of tying it to commit volume.
Breaking the JSON Body with Special Characters
Release names and notes can contain quotes and newlines that break a hand-built JSON string in a curl step, and the request fails with an invalid JSON error. Keep the interpolated text simple, like the tag name and a URL, or use the CLI, which takes the tweet as a plain argument and handles the API call for you.
Identical Text on Every Release
A workflow that tweets the exact same sentence each time looks like a bot and gives followers no reason to engage. Include the version number and release link at minimum, and consider rotating between a few templates. Duplicate text can also be rejected at posting time, so uniqueness protects reliability as well as engagement.
Frequently Asked Questions
What is the easiest way to tweet from GitHub Actions?
A single curl step calling OpenTweet's REST API is the lightest option, since it needs no dependencies. If you prefer a friendlier interface, install @opentweet/cli in a step and run opentweet tweet. And if you only want release announcements, the GitHub connector in the OpenTweet dashboard does it with no workflow file at all.
How do I keep my API key secure in GitHub Actions?
Store it as an encrypted repository secret named OPENTWEET_API_KEY and expose it to the step via the env block. GitHub masks secret values in logs. Never paste the key directly into your workflow YAML, and rotate the key from your OpenTweet dashboard if it ever leaks.
Do I need a Twitter/X developer account to do this?
No. OpenTweet handles the connection to X for you. Your workflow only talks to OpenTweet's API with your ot_ API key, and OpenTweet posts to the X account you connected in your dashboard. There is no X API application, approval process, or token juggling on your side.
Can I schedule the tweet instead of posting immediately?
Yes. With the REST API, send a scheduled_date instead of publish_now and OpenTweet posts it at that time. With the CLI, pass --schedule with a date and time, for example --schedule "2026-05-15 09:00". This is useful when releases ship at odd hours and you want the announcement to land during peak engagement.
How much does it cost to post to Twitter from GitHub Actions?
OpenTweet plans start at $11.99/month for Pro, which includes API access. Advanced is $29/month and Agency is $49/month for more accounts and higher limits. All plans include a 7-day free trial, so you can wire up your workflow before paying anything.
Can I post to multiple X accounts from CI?
Yes. OpenTweet supports multiple X accounts on Advanced (3 accounts) and Agency (10 accounts) plans. In the REST API, pass x_account_id in the request body to target a specific account. In the CLI, pass the --account flag. This lets one workflow announce releases on both a product account and a personal account.
Ship It, Then Tweet It Automatically
One secret, one workflow step. Free 7-day trial.