この記事は Otaku Advent Calendar 2025 の24日目の記事です。
突然ですが…………
今日は誕生日です!!!!!
その証拠に Twitter 1 の私のプロフィール画面(https://twiter.com/gecko655) では風船が飛んでいます。

…
……
………
というのが冗談であることは、私の長年のフォロワーは全員ご存知のことかと思います。念の為知らない方向けに説明すると、私の Twitter アカウントでは毎日風船が飛んでいます。 昨日も一昨日も風船が飛んでいましたし、きっと明日も風船が飛ぶでしょう。
これはなにをしているのかというと、↓のリポジトリに置いてあるスクリプトを用いて、 Twitter のアカウントの誕生日設定を毎日0時頃2に当日の日付に変更しています。 これにより、私の Twitter アカウントはいつ見ても365日風船が飛び続けており、「今日はお誕生日です。」の表示が出続ける状態になっています。
そして、このスクリプトを起動して、初めて誕生日の自動更新に成功した日が、10年前のちょうど今日である2015年12月24日でした。 すなわち、今日は「今日は誕生日です」の10周年記念日です!
↑初めて Twitter の誕生日の自動更新をスクリプトで成功させたときのツイート自動で誕生日が更新されたぞ!!!!
— gecko655 (@gecko655) 2015年12月23日
この記事では、なぜ Twitter で毎日風船を飛ばすようになったのか、この10年間で起こった出来事等々を語っていきたいと思います。
なぜ毎日風船を飛ばすのか
そもそも、私は人に誕生日がバレたくありません。 誕生日はその人の個人情報であるばかりでなく認証情報として使われることが有り、みだりに人に教えるのはセキュリティ的によろしくないと思っているからです。
誰だって自分の誕生日人に知られたくないでしょ
— gecko655 (@gecko655) 2021年6月20日
例えば、(どことは言いませんが)ある病院の窓口で作らされたアカウントでは、パスワードは誕生日から勝手に決められ、ユーザーが自身で変更する方法は全く用意されていませんでした。 この病院の診察券をどこかで落としてしまい、そこから SNS を追跡するなどして誕生日がバレてしまうと、 ID とパスワードが揃ってしまい、不正な認証が通ってしまう危険があるわけです。
また、多くの Web サービスの「パスワードの再発行」画面では誕生日を要求してきます。 今でこそパスワードレスが普及し、誕生日を使うパスワード再発行フォームは珍しくなりましたが、10年前は当たり前にあったように思います。 パスワード再発行を他人に使われてアカウントを盗まれないようにするためにも、人に誕生日は教えたくないなと思っています。

7pay のパスワードリセットがヤバかった例攻撃対象者のメールアドレスと誕生日が分かっていれば、攻撃者のメールアドレスにパスワード再設定用のURLが届く。やってみたらホンマに届いた。 https://t.co/mmrNQVD5eT
— Takashi SASAKI 佐々木隆志 (@TakashiSasaki) 2019年7月3日
↑これと考えは似ているかもしれないこちら母親の旧姓になります。 pic.twitter.com/Ma0pxD1sZE
— やす⋈尾鷲市移住&テレワーク中 (@hirayasu) 2021年1月1日
というわけで、私は特に必要性がない場合3、誕生日を公開しないようにしています。
で、誕生日を公開しないとなると Twitter の誕生日欄は常に空白になり、私のアカウントでは風船が全く飛ばない状態になってしまうわけですが、 せっかく風船機能があるのに使えないのはつまらないですよね?
そこで、逆に風船を毎日飛ばすことを思いつきました。 毎日 Twitter の誕生日を更新すれば、たとえ真の誕生日に風船が飛んでいても、私のフォロワーの皆さんは私の真の誕生日に風船が飛んでいることに気付けないわけです。
木を隠すなら森の中
— gecko655 (@gecko655) 2016年4月20日
誕生日を隠すなら誕生日の中
この10年で起きたこと
2015年:初期実装
Twitter に、誕生日を更新する公開 API は存在しません。 これはイーロンマスク体制による API 有料化/廃止で API が消えたとかとかではなく、最初からありません。 普通の人は誕生日の更新ってしないらしいですからね。 非公開 API を適当に HTTP POST することで更新できないかと検討したものの4、うまくいく方法は見つかりませんでした。
誕生日の日付だけ変えた全く同じリクエストを投げてるはずが403が返ってくるな…
— gecko655 (@gecko655) 2015年11月7日
そのため、誕生日の更新はブラウザのエミュレート(スクレイピング)による、 Twitter Web の操作が必要となりました。
初期の実装は 「当時借りていたさくら VPS5 + Docker + Selenium for Ruby」6 という構成で、これを OS の cron で毎日日付が変わったときに起動して誕生日を更新するというものでした。 これは見事成功し、2015年12月24日に初めて cron による無人での自動更新に成功しました7。

2016年~2018年 Selenium やサーバーの運用
当時の Selenium はなんか挙動が不安定で、気がついたら誕生日の更新が止まっていて風船が飛ばない日がよく発生していました。
Selenium 2.50.*だと(Seleniumの)セッションをquitしたはずなのにプロセスが生き残っていてメモリをがっぽり持ってるので数セッションやると応答が激重になるかOOMでしぬ
— gecko655 (@gecko655) 2016年2月12日
また、私のサーバー管理が雑すぎてセキュリティ的にまずい時期もありました。
当時まだ大学院生でサーバー知識がゴミだったので許してほしい毎日Twitterの誕生日を変えるやつ、ファイヤーウォールがアレすぎてSelenium鯖が外部から大量に攻撃されてちょくちょく動いてなかったことがわかった
— gecko655 (@gecko655) 2016年2月26日
2019年 puppeteer への移行

Puppeteer は2018年1月12日にリリースされた、軽量なスクレイピングツールです。
当時、 Selenium が謎の死を遂げて誕生日更新に失敗するのに嫌気が差していた私は、最近リリースされた Puppeteer というやつが軽量に動作していいらしいぞという噂を聞いて、実際に移行を行いました。
これにより実装は「さくら VPS + Docker + Puppeteer(node.js) + OS cron」という構成になりました。
結果的にはこれは大変良い判断で、 Selenium と比べ puppeteer では謎の死が発生しにくくなり、可用性が一気に上がりました。
2020年 GitHub Actions への移行
2019年の Puppeteer への移行により、 Puppeteer やサーバーインフラに起因する、すなわち私が原因の障害は少なくなっていましたが、この年は Twitter 側で仕様変更が度々発生し、スクレイピング実装の修正が必要になりました8。 公開 API ではなくスクレイピングというグレーゾーンな技術を使っているので仕方のないことですね……
また、社会人として昼間仕事をしていると、さくら VPS に置いている cron の面倒を見るのもだんだんつらくなってきました。
ちょうどいいことに、2019年11月から GitHub Actions が一般利用開始され、気前のいい事にパブリックリポジトリにおいては一定の実行時間までは無料で利用できるようになりました。
ありがたいことに Github Actions は cron 機能も内包していて9、誕生日を毎日0時に更新するのにとても都合が良いことがわかり、2020年1月に GitHub Actions に乗り換えました。
GitHub Actionで誕生日を変更するのを実験している
— gecko655 (@gecko655) 2020年1月18日
ここまででお気づきの方もいるかも知れませんが、この変更により、初期実装で使っていた技術構成はすべて他の技術に置き換えられてしまっていました。テセウスの船状態です。
当初selenium+cron+Docker+さくらVPSで構築してからいろいろあって現在ではpuppeteer+GitHub Actionsとなったので、当時のものはもう何も残っていない
— gecko655 (@gecko655) 2020年1月18日
2020年 pixe.la 導入
誕生日の自動更新の可用性が実際どのくらいあるのかが気になった私は、過去の誕生日更新成功率が何%あったのかを測定してみたくなりました。可用性99.9%みたいなことが言えると なんかかっこいい ですよね。
pixela は、草を生やせる Web サービスです。 ユーザー登録し、日付を指定してincrement APIを叩くと、その日に草が生えた状態の画像を生成してくれます。
このサービスを2020年5月に導入し、リポジトリの README に草画像を載せることで、誕生日更新が直近ではどのくらい安定して実行できているのかを視覚的に表示することができるようになりました。

これまで1年間で合計118誕生日 ←わかる
— gecko655 (@gecko655) 2020年5月18日
今日は1誕生日 ←なるほど
これまでの最大/最小/平均誕生日は1誕生日 ←難しい pic.twitter.com/urxxj2TmTs
2021年 2FA 対応、 UA 偽装、新しいログインフローに対応……
実は、誕生日の自動更新を行っている都合上、当時の私の Twitter アカウントには二段階認証を設定することができない状態でした。 また、二段階認証の設定をしていない Twitter アカウントを使っていると、誕生日更新の直後に人間が Twitter にアクセスした時に毎日 reCAPTCHA を要求される状態でした。
10年以上Twitterしてる人はわかると思うんですが、スクリプトで毎日誕生日変えて毎日風船を飛ばしていると、毎日TwitterさんがreCAPTCHAを求めてくるようになります。
— gecko655 (@gecko655) 2020年8月17日
— gecko655 (@gecko655) 2020年8月20日↑こういうの
アクセス元が急激に変化しているのを不審に思った Twitter のセキュリティ機能が作動しているぽかったのですが、「まあ誕生日更新できているし、毎日 reCAPTCHA すればいいか~」くらいに思っていました。
ところが、2021年3月、銀行 ATM イーネットの公式アカウントが乗っ取られる事件が起きました10。
今回の事件を見て、流石に対策しないとまずいなということで、本腰を入れて二段階認証をアカウントに設定しつつ、誕生日の自動更新時も認証が通るように実装を修正しました。
ちなみに、TOTPによる二段階認証をスクレイピングツールで突破するのは非常に簡単です。

また、 User Agent の偽装が必要になったり、 Twitter 側のログインページのデザインが大きく変更されたり、ログインフォームの 細かい DOM 構造がコロコロ高頻度に変わるなど、いろいろ変更の大きい一年でした。
デザイン変更でスクレイピングに失敗したことにキレている様子💢💢💢💢💢 pic.twitter.com/6ry2akfMZ9
— gecko655 (@gecko655) 2021年9月18日
2022~2023年 平和(ただしアカウントが凍結した)
この期間、誕生日自動更新の世界は平和で、大変安定的に運用ができていました。
ただし、2022年6月9日10時〜2022年10月6日12時の間、私の Twitter アカウントは凍結されてしまいました。今でも原因は不明です。多分誕生日自動更新とはなんの関係もないと思うのですが……
↓くわしくはこちらの記事へ gecko655.hatenablog.com
(2016年&2020年&)2024年 うるう年の更新に失敗する
2016年と2020年の2月29日は、誕生日更新ロジックがうるう年を考慮していなかったため誕生日の更新に失敗していました。 私の誕生年はうるう年でない1991年なのですが、当時の誕生日更新ロジックは存在しない1991年2月29日を誕生日に設定しようとして落っこちていました。
うるう年の2月29日は、1991年から最も近いうるう年である別の年を誕生年とするようロジックを変更し、2024年2月29日は 誕生日を1992年2月29日に変更して無事風船を飛ばすことに成功しました。
うるう年対応 · Issue #8 · gecko655/everyday-birthday
— gecko655 (@gecko655) 2024年2月28日
2016年、2020年と誕生日化に失敗していましたが、今年の2月29日は無事誕生日とすることができました。 https://t.co/EHHrIHtNfa
生まれて初めての誕生日の閏年、めでたすぎるな
— gecko655 (@gecko655) 2024年2月28日
しかし、翌3月1日に誕生日更新に失敗してしまいました。
あーなるほど……… pic.twitter.com/W8EHyZx1vW
— gecko655 (@gecko655) 2024年2月29日
うるう年の2月29日の次の日(3月1日)の誕生日更新時に、誕生日入力のフォームに(閏年でない)年→月→日の順に日付を入力すると、 年を入力した時点で 「閏年でない年の2月29日」を一時的に入力したことになり、このとき Twitter の誕生日入力フォームは年部分を消してしまうという仕様があることがわかりました。
というわけで、うるう年対策は2016年、2020年に続き2024年も失敗に終わりました。 今回の「うるう年の3月1日に誕生日が更新できない」問題はすでに修正を実装済みで、次は2028年にその実装が動作するはずです。次はうまく動いてほしいですね……
2025年 ログインを辞めログインセッションを維持する実装に変更&近代化改修
2025年10月7日、 Puppeteer が Twitter へのログインに急に失敗するようになります。
なんだこれは…… pic.twitter.com/CEUIcqGoEz
— gecko655 (@gecko655) 2025年10月7日
どうも、なんらかの方法で Twitter が Puppeteer からのログインを弾くようになったようで、 User Agent 偽装などの突破方法が通用しなくなりました。
Twitter 上で解決方法を検索したところ、「もはやスクレイピングツールでログイン認証を通すのは諦めて、人がログインしたときのセッションクッキーをスクレイピングツールに食わせたほうがいい」という情報を見て、私もそれに追従することにしました11。 ログインが通らなくなったことで一時は誕生日更新の死を覚悟したのですが、なんとかなってよかったです。
終わりを覚悟したときの様子。なんとかなってよかった2015年12月から維持し続けてきたぼくの誕生日ですが、いよいよこれで終わりかもしれません……………https://t.co/RiblNPO9ZH
— gecko655 (@gecko655) 2025年10月7日
その他、 Puppeteer に移行して以来コードベースが2019年当時からほとんど変わっていなかったため古臭いコードになっていた12のを、2025年の AI Agent パワーでいい感じに書き換えたりなどしました。AI は便利でいいですねぇ。
こんな長く書くつもり無かったのに10年分を振り返ったらめっちゃ長くなっちゃった。
また人を騙してしまった
毎日 Twitter のプロフィール画面で風船を飛ばすのはとても楽しいのですが、たまに新規のフォロワーを迎えると誤解が生じることがあります。
↑誤解が生じた例@gecko655 きょうはありがとうございました(フォローも)!!もろもろよろしくお願いします!
— のーす (@northm36) 2022年2月27日
きょうお誕生日だったのですね。。おめでとうございます!!

大きな問題が発生しているように見えますが、初対面の人とのトークデッキとして使えるので便利さが勝っています。 これからも人を騙し続けていこうと思います。
なお、これまでの人を騙してきた履歴はgecko655(@gecko655)/「また人を騙してしまった」の検索結果 - Twilog (ツイログ)で確認できます。

今日が誕生日であることが当たり前すぎて人に指摘されるまで人を騙していることに気づいてないんだよな
— gecko655 (@gecko655) 2024年10月14日
Twitter 以外の SNS では
Misskey
Misskey には誕生日を変更する API が存在します! 誕生日を変更するニーズが満たされていてとても良いですね。
Twitterと比べてmisskeyの誕生日変更は
— gecko655 (@gecko655) 2023年2月28日
- APIでできる
- 誕生日を何度変更しても特に警告が出ない
- レートリミットも(多分)ゆるゆる
なのに、誕生日はちゃんとユーザープロフィール画面で祝ってくれるので、やましい気持ちにならずに気持ちよく毎日誕生日を変更することができる。
Misskey の誕生日を更新するリポジトリも作っており、運用していました が、 Misskey を全然使わなくなってしまったので、いつの間にか止まってました……
— gecko655 (@gecko655) 2018年8月10日
Facebook で誕生日を変更できるのは1回だけのようです。残念。
仕方がないので4月1日(エイプリルフール)を設定してあります。
Instagram, Bluesky, mixi2
案外、多くの SNS には誕生日の設定がありません。
もし今後の機能追加で誕生日の設定ができるようになったら、誕生日を毎日更新できるか検証したいなと思っています。
mixi2 でスクレイピングをするのはあんまりやりたくないですが……
まとめ
思い返すと色々なことが有りましたが、数々の仕様変更に耐えながらなんとか10年間毎日誕生日を維持することができました。 今後も Twitter の機嫌がよほど悪くならなければ、毎日誕生日を維持していこうと思っています。
そして、ソースコードは GitHub 上で無料公開13しています。 もしよろしければ、皆様も毎日を誕生日にして、365日風船を飛ばしてみませんか14? README.md の説明が不足している気がするので、わかりにくいところあれば Issue などにてご連絡ください。README.md への加筆を検討します。
- この記事では、 https://twitter.com でアクセスできる SNS サービスのことを一貫して "Twitter" と呼びます。↩
- 日本時間↩
- SNS 以外の Web サービスでも、誕生日の入力が必要なときはなるべく真の誕生日以外の日付を入力するようにしています。ただし、金融系、 EC サイトなどのお金が絡む Web サービスでは、誕生日の照合を取ってくる場合があるので、真の誕生日を入力しています。↩
- いわゆるリプレイ攻撃。今改めて考えると、 nonce とかリクエストハッシュとかで失敗していたんじゃないかと思う。↩
- 一番やっすいプランだったはず↩
- 当時のリポジトリ https://github.com/gecko655/everyday-birthday/tree/05b53a9615374b9ee7ea16f3f7db15b622d03899↩
- デバッグの意味では12月22日に初めて成功していたらしい https://x.com/gecko655/status/678979873818284032↩
- 画面レイアウトが変わるだけの簡単なやつは対応するだけでよいのだが、ログインチャレンジを求めてくることがあるのは画面遷移が変化して困った↩
- 余談ですが、さくら VPS の時に辛かった「 cron 実行のときだけ PATH が違うせいで、マニュアル実行したときと動作が違う」みたいなことも発生しなくなったのが地味に嬉しかった↩
- 現在は鍵垢みたいですね…… https://x.com/enetATM↩
- 後日、やっぱり UA 偽装でなんとかなるという報告が上がってきたので、スクレイピングによるログインは引き続きできた説がありますが、戻すのもめんどくさくて現在もセッションクッキーを使う実装のままになっています https://github.com/mikf/gallery-dl/issues/8362#issuecomment-3411493729↩
- 2020年に開発停止された moment.js を使っているとかパッケージ管理が yarn v1とか。↩
- The MIT License (MIT) Copyright (c) 2015 gecko655 https://github.com/gecko655/everyday-birthday/blob/master/LICENSE↩
- ただし、このソフトウェアを使ったことによって被ったいかなる損害について私は責任を取りません↩