🌐 Language / Idioma: Español | English
Turns any technical Markdown article into a bilingual LinkedIn post — ready to publish — using Google Gemini and GitHub Actions. No Zapier, no Make, no third-party platforms.
You paste a URL → GitHub Actions downloads the article
→ Gemini generates the copy → A GitHub Issue is created
→ You review, edit, and publish on LinkedIn
There is no automatic publishing. You always have the final say.
- Prerequisites
- Step 1 — Get your Gemini API Key
- Step 2 — Configure the GitHub Secret
- Step 3 — Create repository labels
- Step 4 — Prepare your article URL
- Step 5 — Run the workflow
- Step 6 — Review your Approval Room
- Step 7 — Publish on LinkedIn
- Troubleshooting
- Architecture & Security
Before you start, make sure you have:
- A GitHub account (you already have one if you're reading this).
- Access to Google AI Studio to generate a free API Key.
- A Markdown article accessible via a public URL (GitHub, Gist, etc.).
You don't need to install anything on your computer. All processing runs in the GitHub cloud.
-
Open Google AI Studio in your browser.
-
Click the "Create API key" button.
If it's your first time, it may ask you to create or select a Google Cloud project. Pick any or create a new one with any name.
-
Copy the generated key. It looks like:
AIzaSyXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -
Save it somewhere safe (like a password manager). You'll need it in the next step.
⚠️ Important: Never paste this key directly into code or into any file in the repository. We'll handle it securely in the next step.
This is the most important step to keep your credentials safe.
-
Go to your repository on GitHub:
https://github.com/beyondnetcode/linkedin-publisher -
Click the
Settingstab (last tab in the top menu). -
In the left sidebar, expand
Secrets and variables→ clickActions. -
Click the green
New repository secretbutton. -
Fill in the form exactly like this:
Field Value Name GEMINI_API_KEYSecret Paste the key you copied in Step 1 -
Click
Add secret. -
✅ You'll see
GEMINI_API_KEYlisted in the secrets table. Done.
The
GITHUB_TOKENdoes not need to be configured. GitHub generates it automatically on every workflow run.
Labels let you easily filter all your drafts. You only need to do this once.
-
Go to the
Issuestab of your repository. -
Click the
Labelsbutton (next to the search bar). -
Click
New labeland create the first label:Field Value Label name linkedin-draftColor #0077B5(LinkedIn blue) -
Click
Create label. -
Repeat to create the second label:
Field Value Label name pending-reviewColor #FFA500(orange) -
✅ Both labels are ready. All drafts will be tagged automatically.
What if I skip this step? The workflow will still work, but you'll see a warning in the logs. The Issue will be created without labels.
The workflow needs the raw URL of your Markdown article. This URL returns the plain text content, which is what Gemini reads.
- Navigate to the
.mdfile in your repository. - Click the
Rawbutton (top-right corner of the code viewer). - Copy the URL from the browser address bar. It will look like:
https://raw.githubusercontent.com/YOUR_USER/YOUR_REPO/main/article.md
- Open your Gist at
https://gist.github.com/YOUR_USER/GIST_ID. - Click
Rawin the top-right corner of the file. - Copy the URL. It will look like:
https://gist.githubusercontent.com/YOUR_USER/GIST_ID/raw/article.md
Any URL that returns plain Markdown text will work, as long as it's public and accessible without authentication.
⚠️ Common mistake: Pasting the GitHub page URL (with the visual interface) instead of the raw URL. If the URL containsgithub.com/USER/REPO/blob/, that's the rendered view — you need the one withraw.githubusercontent.com.
-
Go to the
Actionstab of your repository. -
In the left panel, click
📝 LinkedIn Post Drafter. -
You'll see a yellow banner saying "This workflow has a
workflow_dispatchevent trigger." Click theRun workflowbutton on the right. -
A small form will appear. Fill it in:
Field What to enter Use workflow from Branch: main(leave as is)Public (raw) URL of the Markdown article Paste the URL from Step 4 -
Click the green
Run workflowbutton. -
The page will refresh and you'll see a new run with a spinning yellow circle (⏳ in progress).
-
Click on that run to see real-time logs. You'll see messages like:
📄 Downloading article from: https://raw.githubusercontent.com/... ✅ Article downloaded successfully (4821 characters). 🤖 Sending article to Gemini (gemini-2.5-pro)... ✅ Response received from Gemini (1203 characters). ✅ Gemini JSON validated: post_es ✓ | post_en ✓ | prompt_imagen ✓ 📋 Creating GitHub Issue as Approval Room... ✅ Issue created successfully: https://github.com/beyondnetcode/linkedin-publisher/issues/1 -
When finished, the circle turns green (✅). The entire process takes 20 to 40 seconds.
-
Go to the
Issuestab of your repository. -
You'll see a new Issue created automatically with the title:
📝 [LinkedIn Draft] article-name -
Open it. You'll find three sections:
The complete LinkedIn-ready post in Spanish. Includes the opening hook, body, and closing call to action.
The same post adapted to English, optimized for English-speaking audiences.
A code block ready to copy and paste into your preferred image tool (Midjourney, DALL·E 3, Adobe Firefly, Google Imagen, etc.). The prompt already specifies:
- Hyperrealistic photographic style
- 4:5 aspect ratio (vertical, perfect for LinkedIn)
- No text or artificial 3D elements
A verification list to make sure the post meets your standards before publishing.
-
Edit the Issue if you want to adjust any text. Click the pencil icon (✏️) in the Issue body.
-
When satisfied, close the Issue by marking it as
Closed as completed.
-
Copy the post text (Spanish, English, or both) from the Issue.
-
Generate the image using the prompt from the Issue in your preferred tool.
- Midjourney — Paste the prompt in Discord with
/imagine - DALL·E 3 — In ChatGPT Plus, ask it to generate the image with the prompt
- Adobe Firefly — Paste the prompt in "Text to image"
- Google Imagen — Available in Google AI Studio
- Midjourney — Paste the prompt in Discord with
-
On LinkedIn, click "Start a post".
-
Paste the post text.
-
Attach the generated image (recommended format: JPG or PNG, 4:5 ratio).
-
Publish. 🎉
Cause: The secret is not configured or has a different name.
Solution:
- Go to
Settings→Secrets and variables→Actions. - Verify the secret is named exactly
GEMINI_API_KEY(case-sensitive). - If it doesn't exist, create it following Step 2.
Cause: The article URL is incorrect or the file is not public.
Solution:
- Open the URL in your browser. You should see the plain Markdown text.
- Make sure you're using the raw URL (see Step 4).
- Verify the repository or Gist is public.
Cause: Gemini returned an unexpected response (can happen with very short or very long articles).
Solution:
- Verify the article has substantial content (minimum 300 words).
- Re-run the workflow — Gemini occasionally fails intermittently.
- If it persists, check the full logs in the
Actionstab to see Gemini's exact response.
Cause: The linkedin-draft or pending-review labels don't exist in the repository.
Solution: Create them following Step 3. This doesn't affect the Issue content, only its categorization.
Cause: GitHub Actions may be disabled.
Solution:
- Go to
Settings→Actions→General. - Select "Allow all actions and reusable workflows".
- Save changes.
[You] ──workflow_dispatch──▶ [GitHub Actions]
│
fetch(ARTICLE_URL)
│
▼
[External server]
Plain text .md article
│
Gemini API (GEMINI_API_KEY)
│
▼
[Google Gemini 2.5 Pro]
JSON: post_es, post_en, prompt_imagen
│
GitHub API (GITHUB_TOKEN)
│
▼
[Issue in your repository]
│
▼
[You] ✅ review and publish
| Credential | Where it lives | Appears in logs? | Leaves the repo? |
|---|---|---|---|
GEMINI_API_KEY |
GitHub Encrypted Secret | ❌ Never | ❌ Never |
GITHUB_TOKEN |
Generated by Actions per run | ❌ Never | ❌ Never |
linked-publisher/
├── .github/
│ └── workflows/
│ └── draft.yml ← Defines the workflow (trigger, permissions, steps)
├── scripts/
│ └── generate.js ← Main engine: fetch → Gemini → Issue
├── .gitignore ← Excludes node_modules and .env from the repo
├── package.json ← Dependencies and ESM configuration
├── README.md ← Manual in Spanish
└── README.en.md ← This manual (English)
| Technology | Version | |
|---|---|---|
| Runtime | Node.js 22 LTS | v22.16.0 |
| AI | Google Gemini 2.5 Pro | — |
| CI/CD | GitHub Actions | — |
| npm Package | Version | Purpose |
|---|---|---|
@google/genai |
^0.7.0 |
Official Google Gemini client |
@actions/github |
^6.0.0 |
GitHub API client (Octokit) |
@actions/core |
^1.10.1 |
Logging and error handling in Actions |
node-fetch |
^3.3.2 |
HTTP article download |
Made with ☕ and Gemini · beyondnetcode