Introduction

It’s tedious to manually post to social media every time you update your blog, isn’t it? I recently implemented a feature that automatically posts to X (formerly Twitter) when a new article is published on this blog. While this feature might seem simple at first glance, the implementation presented more challenges than expected. In this article, I’ll share in detail the problems I encountered during implementation and how I solved them.

What I Tried to Implement

Requirements

  • Automatically post to X when a new article is added to the blog
  • Post content includes article title, description, tags, and URL
  • Mechanism to prevent duplicate posts
  • Draft articles are excluded from posting
  • Ability to skip automatic posting when needed

Services and Technologies Used

  • GitHub Actions: Workflow execution environment for automation
  • X API v1.1: Tweet posting API (free plan)
  • twitter-api-v2: X API client library for Node.js
  • Astro: Static site generator for the blog

Challenges Encountered and Solutions

1. ES Module Error

Problem: The following error occurred on first execution

ReferenceError: require is not defined in ES module scope

Cause: Since the project uses "type": "module", CommonJS require cannot be used

Solution:

  • Changed file extension from .js to .mjs
  • Rewrote require to import statements

2. Authentication Error (401 Unauthorized)

Problem: Despite correctly setting API keys, 401 errors persisted

Investigation Process:

  1. Checked GitHub Secrets configuration
  2. Verified permissions in X Developer Portal
  3. Regenerated Access Token
  4. Investigated differences between API v2 and v1.1

Real Cause:

  • App was created as “Standalone Apps”
  • Standalone Apps don’t have write permissions for X API v2
  • Didn’t regenerate Access Token after changing app permissions to “Read and write”

Solution:

  1. Check and change permissions in X Developer Portal
  2. Important: Always regenerate Access Token after changing permissions
  3. Implement fallback processing to v1.1 API

3. File Change Detection Issues

Problem: GitHub Actions couldn’t detect new files

Cause:

  • Insufficient history with fetch-depth: 2
  • Inadequate consideration for manual execution (workflow_dispatch)

Solution:

  • Changed to fetch-depth: 0 to get full history
  • Added special handling for manual execution

4. URL Mismatch

Problem: URLs in tweets were showing as semiramisu.github.io

Cause: Using GitHub Pages default domain

Solution: Fixed to actual domain semiramisu.com

Implementation Key Points

URL Generation with SHA256 Hash

The blog generates URLs by creating SHA256 hashes from filenames:

const fileName = path.basename(file, '.md');
const slug = crypto.createHash('sha256').update(fileName).digest('hex').substring(0, 8);
const postUrl = `https://semiramisu.com/posts/${slug}`;

Duplicate Post Prevention

Saving post history in .github/tweeted/ directory:

fs.writeFileSync(tweetedFile, JSON.stringify({
  tweetId: tweet.id_str,
  timestamp: new Date().toISOString(),
  file: file,
  title: postTitle
}, null, 2));

Skipping Automatic Posts

Skip automatic posting by including [skip-tweet] in commit message:

if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && !contains(github.event.head_commit.message, '[skip-tweet]'))

X API Configuration Notes

Required Authentication Information (OAuth 1.0a)

  1. API Key (Consumer Key)
  2. API Key Secret (Consumer Secret)
  3. Access Token
  4. Access Token Secret

Important Notes

  • Free tier can only use v1.1 API (Standalone Apps)
  • App permissions must be “Read and write”
  • Always regenerate Access Token after changing permissions
  • Monthly post limit is 1,500 (free plan)

The Creation Process of This Article

Interestingly, this article itself was created through dialogue with an AI assistant (Claude). What’s fascinating is how the article came to be:

  1. Feature Implementation Request: “I want to automatically post to X when updating the blog”
  2. Collaborative Debugging: Identifying problems while sharing error logs
  3. Step-by-Step Resolution: Solving ES modules → authentication → API versions in order
  4. Documentation: Looking back at the implementation process and organizing it as an article

What was particularly impressive was the time it took to identify the cause of the 401 error. Checking API key formats, adding debug output, sharing X Developer Portal screen information - it was like a pair programming experience.

Summary

Implementing the X automatic posting feature had more pitfalls than expected. The following points are particularly important:

  1. Understand X API versions and limitations (v1.1 vs v2)
  2. Always regenerate tokens after changing permissions
  3. Read error messages carefully and debug step by step
  4. Pay attention to differences between official documentation and actual behavior

I hope this experience helps those trying to implement similar features. May automation make blog management more efficient!

The Journey to Implementing Automatic X (Twitter) Posting for My Blog

著者

semiramisu

公開日

2025 - 06 - 28

ライセンス CC BY-NC-SA 4.0

コメント