Update: Rendering Static Tweets
A few weeks ago, I wrote a post about rendering static tweets. I’ve made a few important improvements, worthy enough of a new post.
In my original post, I described using a proxy to inject Twitter API headers. This is hacky, and leads to flaky builds, because the build server needs to handle a NodeJS proxy running in the background1. I got this working on Vercel and Cloudflare Pages2, but there was no guarantee the build would pass, and I was constantly re-running failed builds. Neither fun nor productive. In the past few weeks I’ve wanted to remove this functionality from my blog because it’s made it more difficult to preview and deploy.
Last week I was reading Nicholas Whittaker’s blog, specifically a post he wrote about static embeds for tweets and videos (sounds familiar, right?). He’s using workers to handle some of the proxying, but notably, he’s not calling Twitter’s private API, which requires authentication, he’s calling a public one.
I had no idea https://cdn.syndication.twimg.com/
existed. It’s a completely open API you can use for fetching tweets, which means it’s perfect for static sites!
Try it out: curl "https://cdn.syndication.twimg.com/tweet?id=1406108535356678145"
Check out the updated shortcode here.
After some further sleuthing on Nicholas’ blog, I realised you can configure caches in Hugo. This means you can cache calls to getJson
, and push the cache to git. If a tweet ever gets deleted, as long as it exists in the cache3, I can continue rendering the tweet. Neat!
This sounds more complicated than it is. The Hugo shortcode makes a request to
localhost:8080/{tweetId}?auth={authToken}
, the proxy then callshttps://api.twitter.com/1.1/statuses/show?id=${tweetId}
with the same tweet ID and an authentication header. The proxy is on GitHub if you want to take a peek. ↩︎Here is what the build command looked like:
cd twitter-proxy && npm install && node index.js & sleep 5 && echo "Done" && hugo -t hello-friend --baseUrl=$BASE_URL --ignoreCache
↩︎Provided you’ve set
maxAge: -1
, so the cache is never purged. My config is here. ↩︎
On the web
Doing a Jack Baty...?
Fri Jun 20 2025 by Kev QuirkI used to take notes
Thu Jun 19 2025 by joelchrono's websiteDoing my cloud exit (kind of)
Fri Jun 13 2025 by Stan's blogSolving Queuedle
Sat May 31 2025 by Andrew Healey's BlogConfiguring Jujutsu
Sat May 24 2025 by oppiliappan's μblog
Generated by openring