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 つのシナリオで行われます。

  1. カード画像(ツイートに添付された外部リンクのプレビュー画像)
  2. プロフィール画像(ツイートやユーザー情報に表示されるアイコン)

これらは、Twitter の内部 API(例: https://api.twitter.com/1.1/statuses/oembed.jsonhttps://cdn.syndication.twitter.com/widgets/timeline/v1)から取得したメタデータに含まれています。widgets.js は取得した JSON をパースし、必要なプロパティ(image_url, profile_image_url など)を抽出して HTML に埋め込むロジックを持っています。

本稿では、実際にスクリプトをデコードし、画像 URL が抽出・挿入されるコードブロックを追跡します。特に fetchOembedprocessTweetDatarenderImage といった関数がキーポイントです。

具体的な手順や実装方法

1. widgets.js の取得と可読化

  1. 取得
    ブラウザの開発者ツール(Network タブ)で https://platform.twitter.com/widgets.js にアクセスし、レスポンスとして返ってくる JavaScript を保存します。
    bash curl -o widgets.js https://platform.twitter.com/widgets.js

  2. 可読化(デミニファイ)
    取得したファイルは圧縮・難読化されているため、uglify-jsprettier で整形します。
    bash npx prettier --write widgets.js

  3. ソースマッピングの確認
    公式が提供している widgets.js.map が存在すれば、マップファイルを同じディレクトリに配置し、IDE のデバッグ機能で元コードに近い形で閲覧できます。

2. 画像取得ロジックの探索

2.1 主要関数の特定

可読化したコードの中で、fetchOembed(OEmbed API を叩く)と processTweetData(取得データをパース)という名前の関数が見つかります。以下は簡略化した抜粋です。

Js
function 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 カード画像取得の流れ

  1. OEmbed 呼び出し
    fetchOembed が呼び出される場所は、renderTweet 関数内部です。ツイート埋め込みの初期化時に、対象ツイートの URL が渡されます。

  2. 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プロフィール画像 に相当します。

  1. 画像レンダリング
    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 を使用します。

Js
function 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_urlnull になる ツイートがカード画像を持たない(リンク先がカード対応外) 代替として author_image_url へフォールバックするロジックを追加
CORS エラーで xhrJSON が失敗 開発環境でローカル HTML を直接開いたため、Twitter の API が null オリジンを拒否 http-server 等でローカルサーバーを立て、http://localhost からアクセス
画像が ..._normal.jpg のままサイズが小さい author_image_url がデフォルトで「normal」サイズで返る URL のサフィックス _normal_bigger へ置換するか、_400x400 版へ書き換える

具体的なコード例(フォールバック&サイズ変更)

Js
function 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> 要素として埋め込みコンテナに挿入
  • ユーザーカードの場合は fetchUserCardprofile_image_url_https を取得し、同様にレンダリング

これにより、画像取得ロジックの全体像と、実装上の注意点(CORS、フォールバック、サイズ調整)を把握できたはずです。今後は、独自の埋め込みウィジェットを作成したり、画像取得のカスタマイズを行う際の土台として活用してください。

参考資料