markdown
はじめに (対象読者・この記事でわかること)
本記事は、Twitter の公式埋め込みウィジェットである widgets.js の内部実装に興味を持つフロントエンドエンジニアや、Web コンテンツのデバッグ・カスタマイズを行う方を対象としています。
この記事を読み終えると、以下ができるようになります。
https://platform.twitter.com/widgets.jsのソースコードを取得し、展開できること- 画像(カード画像・プロフィール画像など)URL を取得している具体的な関数・コードパスを特定できること
- 取得ロジックを自分のプロジェクトで応用したり、トラブルシューティングに活かせること
埋め込みツイートが表示されない、カード画像が正しく取得されないといったケースで、原因を素早く切り分けられるようになるのが本記事の目的です。
前提知識
この記事を読み進める上で、以下の知識があるとスムーズです。
- HTML/JavaScript の基本的な構造と、ブラウザのデベロッパーツールの使い方
- HTTP/HTTPS のリクエストとレスポンスの概念、特に JSON/REST API の取り扱い
- 基本的な正規表現と文字列操作(
match,replaceなど)
概要・背景
Twitter が提供する埋め込みウィジェットは、外部サイトにツイートやタイムライン、モーメントなどを簡単に表示できる便利な仕組みです。その中心にある widgets.js は、ページロード時に自動的に必要なデータを Twitter のサーバーから取得し、DOM に組み込む役割を担っています。
画像 URL の取得は主に次の 2 つのシナリオで行われます。
- カード画像(ツイートに添付された外部リンクのプレビュー画像)
- プロフィール画像(ツイートやユーザー情報に表示されるアイコン)
これらは、Twitter の内部 API(例: https://api.twitter.com/1.1/statuses/oembed.json や https://cdn.syndication.twitter.com/widgets/timeline/v1)から取得したメタデータに含まれています。widgets.js は取得した JSON をパースし、必要なプロパティ(image_url, profile_image_url など)を抽出して HTML に埋め込むロジックを持っています。
本稿では、実際にスクリプトをデコードし、画像 URL が抽出・挿入されるコードブロックを追跡します。特に fetchOembed、processTweetData、renderImage といった関数がキーポイントです。
具体的な手順や実装方法
1. widgets.js の取得と可読化
-
取得
ブラウザの開発者ツール(Network タブ)でhttps://platform.twitter.com/widgets.jsにアクセスし、レスポンスとして返ってくる JavaScript を保存します。
bash curl -o widgets.js https://platform.twitter.com/widgets.js -
可読化(デミニファイ)
取得したファイルは圧縮・難読化されているため、uglify-jsやprettierで整形します。
bash npx prettier --write widgets.js -
ソースマッピングの確認
公式が提供しているwidgets.js.mapが存在すれば、マップファイルを同じディレクトリに配置し、IDE のデバッグ機能で元コードに近い形で閲覧できます。
2. 画像取得ロジックの探索
2.1 主要関数の特定
可読化したコードの中で、fetchOembed(OEmbed API を叩く)と processTweetData(取得データをパース)という名前の関数が見つかります。以下は簡略化した抜粋です。
Jsfunction fetchOembed(url, cb) { var api = "https://publish.twitter.com/oembed?url=" + encodeURIComponent(url); xhrJSON(api, cb); } function processTweetData(data) { var html = data.html; var img = data.thumbnail_url || data.author_image_url; // 画像 URL がここで取得され、後続の renderImage に渡される if (img) renderImage(img, data); }
fetchOembed はツイート URL を渡すと OEmbed JSON を取得し、processTweetData がその結果を受け取ります。thumbnail_url(カード画像)や author_image_url(プロフィール画像)といったプロパティが画像 URL として扱われます。
2.2 カード画像取得の流れ
-
OEmbed 呼び出し
fetchOembedが呼び出される場所は、renderTweet関数内部です。ツイート埋め込みの初期化時に、対象ツイートの URL が渡されます。 -
JSON パース
受信した JSON には以下のような構造が含まれます(実際のレスポンス例):
json
{
"html": "...",
"author_name": "TwitterDev",
"author_url": "https://twitter.com/TwitterDev",
"author_id": "2244994945",
"author_image_url": "https://pbs.twimg.com/profile_images/1234567890/abc_normal.jpg",
"thumbnail_url": "https://pbs.twimg.com/media/DEF1234.jpg",
"width": 550,
"height": null,
"type": "rich"
}
thumbnail_url が カード画像、author_image_url が プロフィール画像 に相当します。
- 画像レンダリング
renderImage関数は取得した URL を<img>タグに変換し、埋め込みコンテナに挿入します。
js
function renderImage(url, meta) {
var img = document.createElement('img');
img.src = url;
img.className = 'tw-image';
// 必要に応じてサイズや alt を設定
img.alt = meta.author_name + '画像';
container.appendChild(img);
}
2.3 プロフィール画像取得の流れ(別パターン)
ツイート本文中に直接画像 URL が埋め込まれているケースは少ないですが、widgets.js は ユーザカード(hover カード)でも画像を取得します。fetchUserCard という関数があり、内部で GET https://api.twitter.com/1.1/users/show.json?screen_name=... を呼び出し、返ってくる JSON の profile_image_url_https を使用します。
Jsfunction fetchUserCard(screenName, cb) { var api = "https://api.twitter.com/1.1/users/show.json?screen_name=" + encodeURIComponent(screenName); xhrJSON(api, function(userData) { var imgUrl = userData.profile_image_url_https; renderUserCard(userData, imgUrl); }); }
このコードは、ユーザーネームにマウスオーバーしたときに実行され、プロフィール画像 がカードに表示されます。
3. ハマった点やエラー解決
| 現象 | 原因 | 解決策 |
|---|---|---|
thumbnail_url が null になる |
ツイートがカード画像を持たない(リンク先がカード対応外) | 代替として author_image_url へフォールバックするロジックを追加 |
CORS エラーで xhrJSON が失敗 |
開発環境でローカル HTML を直接開いたため、Twitter の API が null オリジンを拒否 |
http-server 等でローカルサーバーを立て、http://localhost からアクセス |
画像が ..._normal.jpg のままサイズが小さい |
author_image_url がデフォルトで「normal」サイズで返る |
URL のサフィックス _normal を _bigger へ置換するか、_400x400 版へ書き換える |
具体的なコード例(フォールバック&サイズ変更)
Jsfunction getBestImageUrl(meta) { // カード画像が無い場合はプロフィール画像へ var url = meta.thumbnail_url || meta.author_image_url; if (!url) return null; // プロフィール画像は _normal → _bigger へ変換 return url.replace('_normal', '_bigger'); }
4. 実装例:自前の埋め込みウィジェット
以下は、widgets.js のロジックを抜粋し、シンプルな埋め込みスニペットを作る例です。
Html<div id="my-tweet"></div> <script> function loadTweet(url) { fetch(`https://publish.twitter.com/oembed?url=${encodeURIComponent(url)}&omit_script=true`) .then(r => r.json()) .then(data => { const container = document.getElementById('my-tweet'); container.innerHTML = data.html; // 画像取得・挿入 const imgUrl = data.thumbnail_url || data.author_image_url; if (imgUrl) { const img = document.createElement('img'); img.src = imgUrl.replace('_normal', '_bigger'); img.style.maxWidth = '100%'; container.appendChild(img); } }) .catch(console.error); } loadTweet('https://twitter.com/TwitterDev/status/1336401443172806657'); </script>
このコードは widgets.js が行う主要なフロー(OEmbed 取得 → 画像 URL 抽出 → DOM へ挿入)を手軽に再現しています。実際の widgets.js では、レスポンシブ対応、アクセシビリティ属性、テーマ切替(ライト/ダーク)などの高度な処理が追加されていますが、コアロジックは上記例で把握できます。
まとめ
本記事では、Twitter の公式埋め込みスクリプト widgets.js が画像 URL を取得する具体的な箇所とフロー を解説しました。
fetchOembedで OEmbed API を呼び出し、JSON に含まれるthumbnail_url(カード画像)とauthor_image_url(プロフィール画像)を取得processTweetDataが取得した URL をrenderImageに渡し、<img>要素として埋め込みコンテナに挿入- ユーザーカードの場合は
fetchUserCardがprofile_image_url_httpsを取得し、同様にレンダリング
これにより、画像取得ロジックの全体像と、実装上の注意点(CORS、フォールバック、サイズ調整)を把握できたはずです。今後は、独自の埋め込みウィジェットを作成したり、画像取得のカスタマイズを行う際の土台として活用してください。
参考資料
- Twitter Publish – OEmbed API
- Twitter API – Users lookup
- UglifyJS – JavaScript parser, minifier, compressor and beautifier
- Prettier – Code formatter