どのサーフェスを使うべきか

埋め込みフレーム: 貴社自身のレイアウト内にレンダリングされる当社のタイル。ネットワークごとに 1 スロット、または複数ネットワークで 1 スロット。

独自のボタン: ボタンは貴社がレンダリングし、当社の短時間のポップアップ 1 つがネットワークを処理します。

ホスト型リンクページ: 当社がホストし、貴社のロゴとカラーが反映されたページ。ユーザーは貴社のアプリを離れて使用します。
ウィジェットの 2 つの行は 2 つの統合ではなく、1 つの統合です。1 回の
init で両方が使えます:
当社のボタンを置きたい場所にフレームをマウントし、それ以外の場所では独自のボタンから popup() を
呼び出します。両者は 1 つのセッションを共有し、同じハンドラーに結果を報告します。ダイレクトモード(Direct Mode)は、当社のスクリプトなしの
同じポップアップです — 厳格な Content-Security-Policy を持つページ、サーバーレンダリングされる
ページ、ネイティブアプリ向けで、この場合はポップアップを自分で開いて監視します。スクリプトの追加
バージョンとそのハッシュを固定するか、ハッシュなしでチャンネルを追従するかのどちらかにしてください。 両方は決して行わないでください — 変化する URL にintegrity 属性を付けると、次のリリースで動作
しなくなります。その URL が指すファイルが正当に変更されるためです。
Pinned version
Tracking v1
推奨するチャンネルは
v1 です。 修正は取り込みますが、破壊的変更を跨ぐことはありません。
latest は定義上メジャーバージョンを跨ぐため、いずれは動作を確認していないバージョンを貴社の
ページに渡すことになります。
各バージョンのハッシュは
manifest.json で公開されており、各
チャンネルが現在何を配信しているかもここに記載されています:
manifest.json
Content-Security-Policy
ページが Content-Security-Policy を送信している場合、2 つのエントリが必要です。どちらも スクリプトの読み込み元ホストを指定します:connect-src エントリは不要で — 当社のフレームは貴社の
ページからではなくフレーム内部から当社の API に到達します — ポップアップ用のエントリも不要です。
ポップアップは貴社のポリシーが管理しないトップレベルのウィンドウだからです。どちらのエントリも実測で
確認済みです: script-src を外すとスクリプトがブロックされ、frame-src を外すとフレームがブロック
されます。
インスタンスの開始
必須のオプションはsession だけです。これはマウントごとではなくインスタンスごとに 1 回
呼び出され、mode: "connect" を指定した
Link Session の作成へのバックエンドのレスポンス —
{ sessionId, token, expiresAt } — を、返ってきたそのままの形で返す必要があります。
Your page
Your backend
network を指定しません — アカウントが許可するすべてのネットワーク
を認可し、どのネットワークを表示するかは貴社のページでマウントごとに決まります。一方で origin は
必ず含みます。これこそがフレームをレンダリングさせる唯一の要素です: フレームは自身を埋め込んでいる
ページをその値と照合し、それ以外の場所ではレンダリングを拒否します。
トークンの期限が切れる前に当社が session を再度呼び出すため、終日開きっぱなしのページでも
ウィジェットは動作し続けます。reject した呼び出しや、トークンを返さなかった呼び出しは、0.5 秒後、
次に 1 秒後の計 2 回再試行され、その後に諦めて error を発行します。つまり 1 回のリフレッシュで
貴社のエンドポイントへの呼び出しは最大 3 回です。
スロットのマウント
スロットごとに 1 回のmount です。1 つのネットワーク、複数、またはセッションが許可するすべてを
要求できます — 粒度は貴社次第なので、スロットは既存のテーブルの 1 行にも、すべてをまとめた 1 つの
パネルにもなります。
mount は CSS セレクタまたは要素を受け取り、{ unmount, element } を返します。ターゲットが何にも
一致しない場合は throw します — ほとんどの場合、まだ存在しないスロットが原因なので、マークアップが
ドキュメントに入った後にマウントしてください。
各マウントは 1 つの iframe です。フレームは自身の高さを当社に報告し、当社がそれに合わせてリサイズ
するため、当社のコンテンツの変化に応じて貴社のレイアウトはリフローします。maxHeight を超えると、
フレームはページからはみ出す代わりに内部でスクロールします。サポートする最小のスロット幅は
300px です。
ネットワークキーは Ayrshare 自身のもので、エイリアス表記も使えます: instagram と instagramapi
はどちらも instagramApi を意味し、x は twitter を意味します。ネットワークでないキーはタイルを
レンダリングしません。
独自のボタン
当社のフレームより自社のボタンを使いたいお客様は、代わりにpopup を呼び出します。同じセッション上
で同じフローが実行され、同じハンドラーに報告されます。
popup は { close(), network } を返し、常にハンドルを返します — ポップアップがブロックされた
後(この場合 close() は何もしません)を含めてです。そのため、close() を呼ぶ前にコードで null
チェックをする必要はありません。
ここではすべてのネットワークが動作します。フレームなら自身のパネル内で完結するものも含まれます:
Facebook はハンドオフの説明をポップアップに表示し、Bluesky と X は認証情報フォームを表示し、
LinkedIn、Pinterest、YouTube、Google Business はネットワークへ出て戻ってきます。
プログラミング上の誤りである 3 つのケース — network がない、破棄されたインスタンス、まだ解決して
いないセッション — に対しては同期的に throw します。ブロックされたポップアップはこれに含まれません:
その場合は reason: "popupBlocked" を伴う error が発行されます。ユーザーは何も間違っていないから
です。
一度に開くポップアップは最大 1 つです。2 回目の呼び出しは 1 つ目を閉じ、そちらに
reason: "superseded" の cancelled を報告します。当社のフレームが開いたポップアップは別物で
あり、決して触れられません。そのため、貴社のボタンがマウント済みスロット内で進行中のフローを
キャンセルすることはありません。
セッションがそのネットワークを連携できるかどうかは、スクリプトではなくサーバーが答えます。
Bluesky にスコープされたセッションで LinkedIn を要求すると、拒否がポップアップ内にレンダリング
され、
error として報告されます。スクリプトが確認するのは、ネットワークが指定されたかどうか
だけです。React
スクリプトはフレームワークに依存しないため、React に特別な対応は不要です — ただし、ライフサイクル について最初から正しくしておく価値のあることが 4 つあります。 スクリプトはコンポーネントツリーの外で一度だけ読み込んでください。Next.js ならルートレイアウトのnext/script、Vite や Create React App なら index.html のタグです。コンポーネントごとに読み込む
と、マウントのたびに再実行されます。
ConnectAccounts.jsx
- 開発時には session コールバックが 2 回発火します。 React の Strict Mode は effect を mount → unmount → mount の順に実行するため、インスタンスは作成、破棄、再作成されます。上記の クリーンアップがそれを安全にします。コストは開発時のバックエンドへの 1 回の追加呼び出しだけで、 本番ではゼロです。
- effect の依存配列を安定させてください。 親の render から
mountに直接渡された配列リテラルは 毎回新しい値になるため、それに依存する effect は render のたびにウィジェットを破棄して再構築 します。メモ化するか、上記のように定数にしてください。
イベント
on で購読します。on は購読解除関数を返します。ハンドラーはイベントペイロードと、その発生元の
マウントを受け取ります。ハンドラーを名前で指定したい場合は off(name, handler) が同じ役割を
果たします。
ready と、ネットワークとはまったく無関係な種類の error を除き、すべてが
network を伴います — 下記の error には 2 つの発生源があるを参照して
ください。
このうち 4 つが結末です —
success、unlinked、error、cancelled で、試行ごとにちょうど
1 つが届きます。closed は結末ではなく、結末の後に続くライフサイクル通知です。
click は連携処理が始まる前に発火するため、ブロックされたポップアップや失効したセッションに
よって拒否されることになるクリックも報告します。貴社独自のアナリティクスにはこのイベントを使って
ください。試行が実際に進行していることを意味するのは started です。
Reason
error には 2 つの発生源がある
連携の失敗はそのうち 1 つだけで、それぞれ異なるフィールドを持ちます。
- 連携エラーは
network、code、そして発生元のマウントを伴います。 - セッションエラー — セッションを作成またはリフレッシュできなかった場合 — は
messageのみを 伴います。その時点では何も連携されていなかったからです。
code と network は undefined です。
state でポーリングが不要になる
state は、試行の報告ではなくデータチャンネルです。各フレームはマウント時にネットワークごとに 1 つ
発行し、そのネットワークの現在の状態と、それを保持し始めた since タイムスタンプを伝えます。さらに
状態が変わるたびにもう 1 つ発行されます — トークンが失効して再連携が必要になった場合など、当社側で
発生した変化も含みます。つまり、何もポーリングせずに UI 全体をウィジェットから駆動できます。
値は GET /profiles の include=state が返すのと同じ enum です:
linked、unlinked、identityVerificationRequired、restricted、rateLimited、suspended。
リンク解除
当社のタイルは連携だけでなくリンク解除も行います。ユーザーが接続済みネットワークをクリックし、確認 すると、アカウントが削除されます:action: "unlink"を伴ってclickが発火します。- 削除が保存されると
unlinkedが発火します。
error を報告し、確認ステップでユーザーがやめた場合は cancelled を報告
します。リンク解除失敗の専用イベントはありません。
外観
お客様のスタイルシートはクロスオリジンフレームの内部には届かないため、スタイルはデータとして渡され、 当社がフレーム内で適用します。appearance を CSS カスタムプロパティとして init に渡してください。
受け取らなかったものはそれぞれ当社のデフォルトのままになります。
appearance をまったく渡さない場合、すべてのトークンはデフォルトを保持し、フレームは次のように
表示されます:

デフォルトのトークン: 白のサーフェス、濃いネイビーのテキスト、インディゴのアクセント、8px の角丸。

上記のトークンを適用した後の、同じ 3 つのタイル。
prefers-color-scheme に反応する
ものは意図的にありません — 貴社のページのテーマはユーザーの OS 設定と一致するとは限らず、メディア
クエリは貴社が選んだ色を黙って上書きしてしまうからです。ダークなダッシュボードには、ダークな値を
渡してテーマを適用します。
このトークン一覧は、バージョンを跨いで維持されるサポート対象の契約です。
トークン一覧
そのトークンにとって有効な CSS でない値は、適用されるのではなくコンソールに警告を出して無視
されます。これは見た目以上に重要です:
--ayr-connect-spacing に単位なしの 8 を渡すのはまったく
無害な文字列に見えますが、適用されればそれを読むすべての計算を無効にし、どこにもエラーを出さずに
レイアウトを崩壊させます。長さには単位を付けてください。
ハンドオフ画面に貴社の名前を表示する
ユーザーをネットワークに引き渡す前に、誰を通じて接続しているのかを示す短い画面を表示します。これを 貴社のものにするためのフックが 2 つあり、どちらもバージョン間で安定しています。--ayr-connect-partner-name はラベルを設定します。値がテキストである唯一のトークンなので、CSS
文字列として引用符で囲む必要があります — 引用符のない値は無効で、何もレンダリングされません:
css の background-image で埋めます — 当社のドキュメント内から画像を取得できるトークンは
受け付けられないため、リクエストは貴社が渡した値からではなく、貴社が書いたルールから発生します。
[data-ayr-connect-partner-mark] と [data-ayr-connect-partner-name] は、下記のカスタム CSS の
注意書きの例外です: この 2 つのセレクタは契約の一部であり、バージョンを跨いで維持されます。カスタム CSS
css は、トークンでカバーできないケースのために、すべてのフレーム内に適用される文字列を受け取り
ます。
appearance と css を継承するため、フローの途中で
当社の無個性なデフォルトが現れるのをユーザーが目にすることはありません。
リリース前に知っておくべきこと
セッションが期限切れのポップアップは error ではなく cancelled を報告する
セッションが期限切れのポップアップは error ではなく cancelled を報告する
popup() で開いたポップアップには、トークンが拒否された理由を伝えられません — 伝えるには、まだ
検証していないオリジンを信頼する必要があり、当社のセキュリティモデルはそれを許可しないためです。
そのため、失効したトークンを持つポップアップは閉じられ、error ではなく
reason: "popupClosed" の cancelled として現れます。実際にはこれは稀です: サイレントリフレッシュの前に開かれたポップアップは、開いた時点でトークン
を検証しているため動作し続けます。説明のつかない popupClosed が発生する場合は、session
エンドポイントが新しいセッションを返していることを確認してください。セッションはマウントごとではなくインスタンスごとに 1 つ
セッションはマウントごとではなくインスタンスごとに 1 つ
14 個のマウントは 1 つのトークンを共有し、バックエンドへの呼び出しは 14 回ではなく 1 回です。
スコープの異なるスロット — 一部だけ別の
allowedSocial — が必要な場合は、マウントで絞り込める
ことを期待するのではなく、独自のセッションを持つ 2 つ目の init を実行してください。フレームは宣言したオリジン上でのみレンダリングされる
フレームは宣言したオリジン上でのみレンダリングされる
すべてのセッションは、貴社のページが動作する
origin を保持しており、フレームは何かをレンダリング
する前に、自身を埋め込んでいるページをその値と照合します。別の場所に埋め込まれたフレームは空白の
ままで、イベントも送信しません。登録するホワイトリストも設定項目もありません — セッション作成時に
正しい origin を送ってください。高さは自動的に処理され、イベントではない
高さは自動的に処理され、イベントではない
フレームは高さをスクリプトに報告し、スクリプトがリサイズします。貴社のレイアウトはただリフロー
します。購読すべき resize イベントはなく、貴社側で測定するものもありません。
要件
- Max Pack。ウィジェットのセッションは connect モードのセッションであり、
Max Pack なしで作成すると
code: 504が返されます。Max Pack のないアカウントで connect モードを 有効にする必要がある場合は、サポートにお問い合わせください。 - すべてのセッションに
origin— 貴社のページが動作する正確なオリジン。省略するとcode: 505が返されます。httpsオリジン、カスタムスキーム、http://localhostのいずれでも ない値はcode: 506を返します。 - セッションに
networkを指定しないこと。このパラメータはセッションを ダイレクトモードにするものであり、ダイレクトモードの セッションの URL はスクリプトが期待するものではありません。