· via dev.to (home feed)
X's $0.20 per-link posting fee reshapes how one Bluesky-and-X news bot works
A dev.to build log shows how X's $0.20-per-URL API pricing changed a news bot's design: every story goes to Bluesky free, while only top-ranked sources earn a paid post on X.

X bills per post, Bluesky does not
According to a dev.to write-up, X's API pricing now charges $0.015 for a plain post and $0.200 for any post containing a URL, with no free tier. Bluesky's API costs nothing. Faced with that asymmetry, the author built a Python news bot for a single industry feed and let the pricing decide the architecture: every qualifying story is published to Bluesky, while only stories from well-ranked sources also get paid for on X.
The bot is deliberately minimal — one Python file, a GitHub Actions workflow that runs every 30 minutes, and a posted. state file committed back by the workflow so the next run knows what has already gone out. Each run fetches the previous 24 hours of articles from the APITube news API, drops anything already posted, publishes up to three new stories to Bluesky with a link card and thumbnail, and forwards a subset to X through tweepy. The tested stack, per the post, was Python 3.12 with atproto 0.0.72, tweepy 4.17.0 and Pillow 12.3.0.
A ranking threshold as a budget control
The decisive line in the script is a single constant, X_MIN_OPR = 6: a story is sent to X only if its source has an OpenPageRank of 6 or higher. The author frames this as arithmetic rather than editorial taste. Posting everything that survived the feed filters — 34 stories a day — to X would cost about $204 a month at the URL rate; posting only the top five costs $30. Because Bluesky is free, that threshold is the only thing standing between the two bills.
One day of one feed, measured
Before writing the posting logic, the author measured a single day of the Renewable Energy feed: 270 English articles on 16 September 2026. Two findings stood out. First, the deduplication most bots rely on did nothing — all 270 URLs were distinct and the API's is_duplicate flag caught none of them, because syndicated copies arrive under different domains. Normalising titles, by lowercasing and stripping punctuation, caught 18 duplicates, including one story published six times. Second, the share-image filter did most of the work, cutting 270 articles to 35; adding the OpenPageRank floor left just five.
Arrivals are also lumpy. The busiest 30-minute slot brought 21 articles while the median slot had four, which is why the script caps posts per run instead of flushing whatever arrived.
The long tail of platform constraints
Even the free network imposes rules that shape the code. Bluesky rejects uploaded blobs over 1,000,000 bytes, and five of the 29 thumbnails fetched that day exceeded the limit; shrinking them with Pillow to fit a 1200-pixel box at JPEG quality 85 brought them down to roughly 130-250 KB. Six other images were smaller than the 1200x630 size the API filter promises, and the author notes there is no code fix beyond checking dimensions and skipping the card. Character limits barely register: the longest headline in the sample was 118 characters against Bluesky's 300-grapheme limit, and on X a URL always counts as 23 characters, so every sampled title fit within 280.
Why it matters
When each link post costs $0.20, distribution stops being free plumbing and becomes a line item. Developers running cross-posters, schedulers or syndication pipelines now face the same design change this bot made: rank stories with a metric the code can evaluate, and pay only for the ones that justify it. The split also changes what each network receives from the same bot — Bluesky gets the full feed while X sees a curated top slice — which quietly pushes X toward being a premium channel and free, open APIs toward being the default.
- #x-api
- #bluesky
- #bots
- #api-pricing
- #github-actions