Shoplive Web Player SDK 連携ガイド
ライブコマース配信を Web ページに組み込む手順をミッションに分けてご案内します。ミッション 1 だけで配信は表示されます — 残りは必要なものだけお選びください。
概要 & 要件
Shoplive Web Player SDK は、スクリプトタグ 1 つでライブ配信プレイヤーを Web ページに組み込みます。別途パッケージをインストールしたり、ビルドツールを設定したりする必要はありません。
好きな位置にプレイヤーを直接埋め込む、リンク 1 つで開く、別のページにプレビューを表示する — 必要な方法だけを選んで適用できます。
必要なもの
| 項目 | 確認する場所 |
|---|---|
| Access Key | Shoplive Admin — 配信詳細ページ上部のサマリーカード |
| Campaign Key | Shoplive Admin — 配信詳細ページ上部のサマリーカード |

何を実現したいですか?
ミッション 1 を終えれば画面に配信が表示されます。ミッション 2〜6 は互いに独立しているので、順序に関係なく、必要なものだけ選んで適用してください — すべてをこなす必要のあるリストではありません。
| やりたいこと | 参照先 | |
|---|---|---|
| ページの特定の位置にプレイヤーを埋め込む · 配信リストまで一度に表示する · リンク 1 つで配信を開く | まず | ミッション 1 · 配信を表示する |
| チャットの表示名や入場制限など、ユーザー情報を連携する | 任意 | ミッション 2 · ユーザー情報の連携 |
| クーポン・商品のタップ、ログインが必要な場面などで自社のコードを実行したい | 任意 | ミッション 3 · ユーザー操作を処理する |
| 配信ページ以外でも配信中であることを知らせ、共有リンクから来てもらう | 任意 | ミッション 4 · 他のページでも配信を知らせる |
| 表示中のプレイヤーを自社コードから操作する(クーポンを消す・ミュート・ダイアログ) | 任意 | ミッション 5 · プレイヤーを制御する |
| どのチャネルから流入し、実際に購入したかを集計する | 任意 | ミッション 6 · 計測 — 流入と購入 |
| ブランドのお気に入り・カート・配信リマインド・オークションなど、有効化が必要な機能を組み込む | 任意 | 付録 A · 有効化が必要な機能 |
| 配信を見ている途中で商品ページへ移動しても映像が途切れないようにする | 任意 | 付録 B · PIP |
| SPA · アプリ WebView · RequireJS · ショートフォームとの同居など、特殊な環境に合わせる | 任意 | 付録 C〜F |
プレイヤー画面の各要素の呼び名は画面の用語ガイドにまとめています — ミッションを読んでいて removeBanner が何を消すのか迷ったら戻ってきてください。
shoplive.js)とショートフォーム(shoplive-shortform.js)は別のスクリプトですが、同じ window.cloud.shoplive オブジェクトを共有するため 1 ページに一緒に読み込めます。ユーザー情報は一度渡せば両方に反映され、注意点は 2 製品のプレビューが画面の同じ隅で重なりうることだけです — 詳しくは付録 F、ショートフォームの連携自体はショートフォームガイドをご覧ください。クイックスタート
最短の手順で画面にプレイヤーを表示するサンプルです。細かいオプションは下のミッション 1 からご覧ください。
<script src="https://static.shoplive.cloud/shoplive.js"></script>
<script>
cloud.shoplive.initPlugin({ accessKey: 'YOUR_ACCESS_KEY' });
</script>
<div id="shoplive-player"></div>
<script>
cloud.shoplive.setPlayer("shoplive-player", { campaignKey: "YOUR_CAMPAIGN_KEY" });
</script>
cloud.shoplive は SDK が用意するグローバル オブジェクトです。上のスクリプトが読み込まれると window.cloud.shoplive に initPlugin · setPlayer などの関数が追加されます。そのため import やバンドラーの設定なしに、どのスクリプトからでも cloud.shoplive.… と直接呼び出せます — ただし SDK のスクリプトタグより後で呼ぶ必要があります。使える関数の一覧は関数インデックスにあります。
次のステップ画面の用語ガイド · ミッション 1 から始める →
画面の用語ガイド
プレイヤー画面の各要素の呼び名をまとめたものです。以降のミッション・イベント辞典・コマンド辞典でも同じ用語と同じ番号を使います。removeBanner が何を消すコマンドだったか迷ったら、この表に戻ってきてください。
プレイヤー画面
| 番号 | 要素 | 表示条件 | Web での関連 |
|---|---|---|---|
| ① | 映像エリア | 常時 | playVideo · pauseVideo · videoRefresh(コマンド辞典) |
| ② | ブランドロゴ | 常時 | Shoplive Admin のキャンペーン設定 — コードでは変更しません |
| ③ | キャンペーンタイトル | 常時 | Shoplive Admin のキャンペーン設定 |
| ④ | LIVE バッジ · 視聴者数 · いいね数 | LIVE 限定 | 視聴者数・いいね数は ON_CHANGED_VIEWER_STAT、配信ステータス(開始・終了)は ON_CAMPAIGN_STATUS_CHANGED で受け取れます(ミッション 3 · 通知だけを受け取るイベント)。表示自体は ui.viewerCount · ui.likeCount でオン・オフできるだけです |
| ⑤ | チャットオーバーレイ | LIVE 限定 | 映像の上を流れるチャット。Web から制御する API はありません |
| ⑥ | 商品カード(左下 · NOW) | 常時 | タップすると CLICK_PRODUCT(ミッション 3)· リストを閉じるのは dismissGoodsList |
| ⑦ | 右側のアイコン列(♡ · ? · 💬) | 常時 | いいね · 問い合わせ · チャットを開く。列全体を hideControls · showControls で隠したり表示したりできます |
| ⑧ | ミュートボタン | 常時 | mute · unmute。自動再生の制約により最初はミュートで始まります |
| ⑨ | クーポンバブル | 運営者が発行したとき | タップすると Admin で選んだクリック時の動作がそのままイベントとして届きます(ミッション 3 · ポップアップ)· 削除は removeCoupon |
| ⑩ | お知らせ pill | 運営者が発行したとき | お知らせもタップできます — ⑨ · ⑪ と同じクリック時の動作設定に従います(ミッション 3 · ポップアップ)· 削除は removeNotice |
| ⑪ | イベントバナー · ポップアップ | 運営者が発行したとき | Admin で選んだクリック時の動作がそのままイベント名になります — LINK · LINK_NEW_WINDOW · DOWNLOAD_COUPON · CUSTOM_ACTION(ミッション 3 · ポップアップ)。⑨ クーポン · ⑩ お知らせも同じ仕組みです · 削除は removeBanner |
| ⑫ | 右上のボタン | 常時 | Web では構成が異なります — 下の説明をご覧ください |
モバイルとの違い
| 図の要素 | Web プラグイン |
|---|---|
| ⑫ 最小化(in-App PIP)ボタン | ありません。画面の隅に小さく表示するのは別機能のミニプレビュー(setLiveMiniPreview)で、プレイヤー内のボタンではなく自社から呼び出します |
| ‹ 戻る | あります。タップすると CLICK_BACK_BUTTON — デフォルト動作は history.back() なのでページが戻ります。モーダルで表示している場合は閉じる処理も併せてご覧ください |
| 共有アイコン | あります。CLICK_SHARE_BTN · 共有する URL は shareUrl で指定します。非表示にするには hideShareButton |
| iPhone のステータスバー · ホームインジケーター | アプリ画面の一部なので Web にはありません。Web プレイヤーは用意していただいた div のサイズ(またはモーダル)に合わせて描画されます |
プレイヤー内の UI はほとんどが Shoplive Admin のキャンペーン設定でオン・オフします。コードから変更できるものは ミッション 1 · 画面に何を表示するかにまとめています。
前へ ← クイックスタート次へ → ミッション 1 · 配信を表示する
ミッション 1 · 配信を表示する
表示方法は 3 つあります。どれか 1 つを選べばよく、3 つとも同じ initPlugin() の上で動きます。
| 方法 A · プレイヤーのみ | 方法 B · リンクで開く | 方法 C · ライブページ テンプレート | |
|---|---|---|---|
| 画面に出るもの | プレイヤー 1 つ | プレイヤー 1 つ(全画面) | メイン配信 + 配信リストまで一度に |
| 位置・サイズのカスタム | 自由にできます | 不可(shoplive.show の固定レイアウト) | 領域単位で選択(プレイヤーのみ / リストのみ) |
| レイアウトを自社で組むか | はい — コンテナと周囲の UI を自分で構成します | いいえ | いいえ — Shoplive のテンプレートを使います |
| ユーザー認証の設定 | コード(initPlugin)で設定 | URL の tk パラメータで設定 | コード(initPlugin)で設定 |
クーポン・商品タップなどのカスタムロジック(messageCallback) | 可能 | 不可 | 可能 |
| PIP(商品ページへ移動しても見続ける) | 可能 | 不可 — 自社ページに SDK がありません | 可能 |
| 主な用途 | イベント専用ページ、特定キャンペーンの特設ページ | 広告クリエイティブのランディング | 常設のライブコーナー — 配信が入れ替わり続けるページ |
方法 Aプレイヤーを直接埋め込む
ページを自分で作れる場合はこの方法を使います。好きな位置にコンテナを置いて setPlayer を呼びます。
<script src="https://static.shoplive.cloud/shoplive.js"></script>
<script>
cloud.shoplive.initPlugin({ accessKey: 'YOUR_ACCESS_KEY' });
</script>
<div id="shoplive-player"></div>
<script>
cloud.shoplive.setPlayer("shoplive-player", {
campaignKey: "YOUR_CAMPAIGN_KEY"
});
</script>
プレイヤーはコンテナ div の中を埋めるので、コンテナのサイズと位置はページの CSS で決めます。配信が終わって CLOSED になっても campaignKey はそのままで構いません — 同じキーでアーカイブ再生されます。
div 1 つだけです。スクロールしてもプレイヤーが付いてくるのは、その div に position:sticky を指定しているからで、ページの CSS で自由に決められるということです。動画内のショップは撮影用のサンプルで、文言は英語です。画面に何を表示するか 任意
| オプション | デフォルト | 説明 |
|---|---|---|
ui.viewerCount | true | 視聴者数を表示 |
ui.likeCount | true | いいね数を表示 |
ui.backButton | false | 戻るボタンを表示。タップすると CLICK_BACK_BUTTON が発生し、デフォルト動作は history.back()(ミッション 3) |
ui.shareButton | false | 共有ボタンを表示(共有 URL) |
cloud.shoplive.setPlayer("shoplive-player", {
campaignKey: "YOUR_CAMPAIGN_KEY",
ui: { viewerCount: true, likeCount: true, backButton: true, shareButton: true }
});
チャットや商品リストなどプレイヤー内部の構成はアカウント設定とテーマで決まります。上の 4 つ以外を変更したい場合は Shoplive 担当者までお問い合わせください。
共有ボタンが送る URL 任意
共有ボタンをオンにした場合、共有されるアドレスを initPlugin() の shareUrl で指定できます。指定しなければ現在のページのアドレスが使われます。共有の動作そのものを変える方法と URL の組み立てルールはミッション 3 をご覧ください。
cloud.shoplive.initPlugin({
accessKey: 'YOUR_ACCESS_KEY',
shareUrl: 'https://my-shop.com/live' // 任意 — 省略すると現在のページ
});
常に全画面で 任意
cloud.shoplive.setPlayer("shoplive-player", {
campaignKey: "YOUR_CAMPAIGN_KEY",
isFullScreen: true
});
isFullScreen: true を使うと、SDK がページの <meta name="viewport"> タグを探し、モバイルのピンチズームを抑えるよう値を調整します。このタグがページになければエラーも出さずに無視されるので、あらかじめ下のように入れておいてください。
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover, shrink-to-fit=no">
その他のオプション 任意
特定の状況でのみ使う値です。通常は指定しなくて構いません。
| オプション | 型 | 説明 |
|---|---|---|
hideControls | boolean | true にするとプレイヤーのコントロール UI を隠した状態で開始します。開始後はプレイヤー制御の showControls / hideControls コマンドでも切り替えられます |
playerAlias | string | このプレイヤーに付ける別名。1 ページに複数のプレイヤーがあるとき getPlayer('別名') で正確に取り出すために使います(ミッション 5)。指定しなければ campaignKey で探します |
closePlayerAfterCampaignEnd | number(ms) | 配信終了後この時間が経つと CLOSE_PLAYER イベントが届きます。配信が終わったときにページを片付けたり別の画面へ送ったりするための合図として使う値です — SDK はこのイベントでプレイヤーを閉じませんので、実際に取り除くには destroyPlayer() を自分で呼ぶ必要があります。指定しない場合は、配信終了の30 秒後にプレイヤーが自分で再読み込みし、終了画面に落ち着きます |
chatFilterPatterns | string[] | 正規表現文字列の配列。視聴者が送ろうとしているチャットがいずれかに一致すると送信されず、代わりに ON_FILTERED_CHAT イベントが発生します。独自の禁止ワード ポリシーをコードで載せるときに使います |
passcode | string | リハーサル配信をプレビューするための入場コード。リハーサルに設定された配信は ONAIR になるまでこの値がないと入場できません |
brand | object | ブランドのお気に入り機能を使うときに初期状態を渡します — { identifier, favorite }(付録 A · ブランドのお気に入り) |
描き直しと後片付け
同じコンテナに setPlayer をもう一度呼ぶと、既存のプレイヤーを片付けて新しく作り直します。別の配信に差し替えるときに destroy を先に呼ぶ必要はありません。
逆にコンテナ自体が画面から消えるとき(SPA でコンポーネントがアンマウントされる場合など)は、SDK がそれを検知できず、プレイヤーが内部的に生き残ります。コンテナを取り除く前に destroyPlayer を呼んでください。
cloud.shoplive.destroyPlayer("shoplive-player");
方法 Bリンクで直接開く
ページを新しく作るのが難しい場合は、専用ページを用意せずに Shoplive が提供する shoplive.show ページを URL パラメータだけで呼び出します。ただし SDK は shoplive.show のページ内でのみ動作し、この URL を開く自社ページには読み込まれないため、initPlugin() を呼ぶことはできません。ユーザー操作の処理(ミッション 3)が必要な場合は方法 A または C を使ってください。
https://www.shoplive.show/v1/player.html?ak={access_key}&ck={campaign_key}&tk={ユーザー情報}
| パラメータ | 必須 | 説明 |
|---|---|---|
ak | 必須 | Access Key |
ck | 必須 | Campaign Key |
tk | 任意 | ユーザー情報 — URL エンコードした userObject JSON または JWT(ミッション 2)。ゲスト視聴なら省略 |
userId · userNamegender · age · userScore | 任意 | tk の代わりに使う簡易方式。この 5 つのみ対応しており、tk も一緒に渡すと tk が優先されます(ミッション 2) |
backButton | 任意 | 1(表示)/ 0(非表示) |
shareButton | 任意 | 1(表示)/ 0(非表示) |
共有ボタンのクリック時に渡すページ URL を指定する shareUrl オプション(方法 A 参照)は initPlugin() を直接呼ばないと適用されないため、方法 B では使えません。方法 B でできるのは shareButton=0 で共有ボタン自体を隠すことだけです。
messageCallback も登録できません。方法 Cライブページ テンプレート — プレイヤーと配信リストを一度に
プレイヤー 1 つではなくライブコーナーのページ全体が必要なときに使います。空の div 1 つに setOverall を呼ぶと、その中にメイン配信(配信中、または直近の配信)+ 配信リストが Shoplive のテンプレートで描画されます。どの配信を出すかをコードで決めなくてよいので、配信が入れ替わり続ける常設コーナーに向いています。
<div id="shoplive-overall-area"></div>
<script>
cloud.shoplive.setOverall('shoplive-overall-area');
</script>
setOverall の描画した領域です。この画面では 2 つの領域を離して配置するために div を 2 つに分け、featuredOnly · campaignListsOnly でそれぞれ呼び出しています(どの領域だけを出すか)。リストの配信をタップすると SDK が自動でモーダル プレイヤーを開きます。この動作を自分で処理したい場合は ON_CLICK_CAMPAIGN_LIST_ITEM を登録してください(ミッション 3)。
どの領域だけを出すか 任意
| やりたいこと | オプション |
|---|---|
| デフォルト — メイン配信 + リスト | オプションなし |
| メイン配信(プレイヤー)領域のみ | { featuredOnly: true } |
| 配信リスト領域のみ | { campaignListsOnly: true } |
| メイン配信を特定の配信に固定 | { featuredOnly: true, featured: { fixedCampaignKey: 'YOUR_CAMPAIGN_KEY' } } |
2 つの領域を離れた位置に置きたい場合は、div を 2 つ作り、一方を featuredOnly、もう一方を campaignListsOnly で呼び出してください。
リストの構成を決める 任意
cloud.shoplive.setOverall('shoplive-overall-area', {
campaignListsOnly: true,
campaignStatus: ['ONAIR', 'CLOSED'], // この順に並びます
tags: ['sale', 'new'],
tagSearchOperator: 'OR', // 'OR' いずれか一致 · 'AND' すべて一致
displayTags: ['sale', 'new', 'best'], // リストの上にフィルタータブとして表示
campaignList: { layout: 'HORIZONTAL' } // 'GRID'(デフォルト)| 'HORIZONTAL'
});
| オプション | デフォルト | 説明 |
|---|---|---|
campaignStatus | すべて | 'READY'(予定)· 'ONAIR'(配信中)· 'CLOSED'(終了・アーカイブ)。文字列 1 つ、または配列。配列で渡すと書いた順に並び、同じステータス内では配信予定時刻の新しい順です。この値は campaignListsOnly: true のときだけ効きます — メイン配信とリストを 1 つの div にまとめて描画するデフォルトのモードでは、配信中・予定・アーカイブの 3 セクションが常に出ます |
tags / tagSearchOperator | — | 配信に付けたタグでフィルター。複数あるときは 'OR' / 'AND' を選びます |
displayTags | — | リストの上にフィルタータブとして出すタグ。視聴者がタップして絞り込めます |
skus / goodsIds | — | 特定の商品を含む配信のみ — skus は自社の商品コード、goodsIds は Shoplive 内部の商品 ID |
campaignList.layout | 'GRID' | 'GRID' グリッド · 'HORIZONTAL' 横 1 列スクロール |
campaignList.type | — | 'SECTION' を渡すとステータス別のセクションに分けて表示します |
hasMoreButton | true | リスト下の「もっと見る」ボタン。false にすると 'GRID' では無限スクロールになります |
ascending | ステータス次第 | 並び順。指定しない場合、campaignStatus が 'READY' の文字列 1 つのときだけ昇順(近い配信から)で、それ以外は降順です |
sectionTitles | 既定の文言 | リストのセクション見出しを自社サービスの言い回しに変えます — { onair, ready, closed, all } |
cloud.shoplive.setOverall('shoplive-overall-area', {
sectionTitles: {
onair: 'ライブ配信中',
ready: '配信予定',
closed: '過去の配信',
all: 'すべての配信'
}
});
後片付け
SPA でページを離れるときは destroyOverall を呼びます。第 2 引数に true を渡すと、中に残っているプレイヤーまで併せて片付けます。
cloud.shoplive.destroyOverall('shoplive-overall-area', true);
モーダルで表示する 任意
ページに領域を作らず、ボタンを押したときに画面の上にモーダルとして配信を表示する方式です。バナーやボタンからすぐに配信を開くときに使います。
<button id="open-live">ライブを見る</button>
<script>
document.getElementById('open-live').addEventListener('click', function () {
cloud.shoplive.showFeaturedPlayerModal({ campaignKey: 'YOUR_CAMPAIGN_KEY' });
});
// コードから閉じる
// cloud.shoplive.dismissLayerModalPlayer();
</script>
showFeaturedPlayerModal({ campaignKey, disableHistoryHook: true }) でオフにできます — 代わりに戻るで前のページへ遷移します。完了の確認
- (方法 A)指定した
divの位置にプレイヤーが描画され、配信が ONAIR なら自動再生を試みる(ブラウザの自動再生ポリシーにより制限される場合があります) - (方法 B)URL だけで、専用ページを作らずにプレイヤーが開く
- (方法 C)指定した
divの中にメイン配信と配信リストが描画され、リストの配信をタップするとモーダルが開く - 共有ボタンをオンにした場合、タップすると
shareUrlを指定していればそのページが、指定していなければ現在のページが共有される
前へ ← 画面の用語ガイド次へ → ミッション 2 · ユーザー情報の連携
ミッション 2 · ユーザー情報の連携
setUserObject()・setUserJWT() はユーザー情報を渡すもので、ユーザーを認証するものではありません ログイン(ID・パスワード、ソーシャルログインなど)はすべて自社サイト側で行います。これらの関数はいまの視聴者が誰かを Shoplive に伝えるだけで、チャット・視聴・統計がその会員に紐づきます。Shoplive はユーザーの資格情報を確認しません。JWT 認証では、その情報が自社サーバーが発行し改ざんされていないか(署名)を Shoplive が確認でき、簡易認証(userObject)ではその確認なしに情報をそのまま渡します。ステップ 1 · ログイン状態で選ぶ — 推奨の設定
| ユーザー | 推奨 | 理由 |
|---|---|---|
| 未ログイン | 何も呼び出さない(ゲスト) | ユーザー情報を渡す必要はありません。ゲストのチャット可否は Admin で設定し、不可の場合はチャット入力欄が無効になり「チャットに参加する」という案内が表示されます。ゲストを区別する識別子が必要ならゲスト uid を受け取るを参照してください |
| ログイン (推奨) | setUserJWT() — サーバーが署名した JWT(JWT 認証) | 改ざんできないため、userScore・userType による入場制限のような権限の判定に使えます |
| ログイン(バックエンド作業が難しい場合) | setUserObject() — id・名前などを直接渡す(簡易認証) | クライアントの値を署名なしでそのまま渡します。識別・統計には十分ですが、権限の検証には使わないでください |
| ログイン(Cafe24 · WISA · ゴドモール · Shopify のショップ) | プラットフォーム自動連携 | ショップが既に把握しているログイン状態を SDK が読み取ります。上の 2 つとはどちらか一方で、ユーザー情報を直接渡した場合はそちらが優先されます |
| ログアウト・ユーザー情報のリセット | cloud.shoplive.logout() · または setUserObject(null) / setUserJWT(null) | 設定したユーザー情報を消去し、ゲスト状態に戻ります |
setUserJWT() を呼ぶ直前ごとに)バックエンドから新しく発行した JWT を受け取り initPlugin({ userJWT }) または setUserJWT() → ログアウト時に logout()(または null を渡す)でユーザー情報をリセット。
方法 B(リンクで開く)は同じ JWT を tk パラメータで渡します(ステップ 2)。ステップ 2 · 選んだ方式で呼び出す
ユーザー情報が initPlugin() の時点で分かっていれば、その呼び出しにそのまま含めます。ログイン状態が後から確定する場合(SPA など)は setUserObject() / setUserJWT() を後から呼びます。簡易認証は userId 以外すべて任意で、JWT には別途必須フィールドがあります(ステップ 5 参照)。ゲストは両方とも呼ばなければ大丈夫です。
// 簡易認証 — userId のみ必須、ほかは任意
const userObject = {
userId: "", // 必須 — ログインユーザーの一意な ID。空ならゲスト扱い
userName: "", // 任意 — チャットに表示される名前。未指定の場合はキャンペーン設定により入力を促すか自動生成。禁止ワードは * に置き換えて表示
gender: "", // 任意 — "m" | "f" | 未指定なら空
age: "", // 任意 — 統計では 5 歳単位にグループ化して表示されます
userScore: "", // 任意 — -100〜100 の整数。抽選対象の制限などの基準に使えます
userType: "", // 任意 — 入場制限(Entry Type)設定時に参照される値
profile: "", // 任意 — チャット一覧のプロフィール画像 URL、推奨 64x64px
custom: "", // 任意 — 自由形式のデータ、最大 1KB
canBid: true // 任意 — オークションの入札資格(付録 A · オークション)
};
// 方法 1 — initPlugin() の呼び出しにそのまま含める
cloud.shoplive.initPlugin({ accessKey: "YOUR_ACCESS_KEY", userObject });
// 方法 2 — initPlugin() のあとに別途呼ぶ(ログイン情報が後から確定するとき)
cloud.shoplive.initPlugin({ accessKey: "YOUR_ACCESS_KEY" });
cloud.shoplive.setUserObject(userObject);
// JWT 認証も方式は同じ — ステップ 5 で作ったトークンを渡します
cloud.shoplive.initPlugin({ accessKey: "YOUR_ACCESS_KEY", userJWT: "USER_JWT" });
// または
cloud.shoplive.setUserJWT("USER_JWT");
// ログアウト・ユーザー情報のリセット — 設定したユーザー情報を消去し、ゲスト状態に戻ります
cloud.shoplive.logout();
// または渡した値を null に: cloud.shoplive.setUserObject(null) / cloud.shoplive.setUserJWT(null)
initPlugin() の呼び出し自体がないため、上の userObject を JSON 文字列にして URL エンコードした値を tk パラメータに入れます。JWT はエンコードせずトークン文字列をそのまま入れます。
// 簡易認証
https://www.shoplive.show/v1/player.html?ak=YOUR_ACCESS_KEY&ck=YOUR_CAMPAIGN_KEY&tk=encodeURIComponent(JSON.stringify(userObject))
// JWT
https://www.shoplive.show/v1/player.html?ak=YOUR_ACCESS_KEY&ck=YOUR_CAMPAIGN_KEY&tk=USER_JWT
フィールドが少なければ個別パラメータでも渡せます。userId・userName・gender・age・userScore はクエリパラメータとして直接渡せるので、JSON を作ってエンコードする必要がありません。ただし userType・profile・custom・canBid と JWT はこの方式では渡せないため tk を使ってください。tk も一緒に渡すと tk が優先されます。
https://www.shoplive.show/v1/player.html?ak=YOUR_ACCESS_KEY&ck=YOUR_CAMPAIGN_KEY&userId=MEMBER_ID&userName=NICKNAME
ステップ 3 · ショップ プラットフォームを使うなら — 自動連携 任意
Cafe24・WISA・ゴドモール・Shopify で構築したショップなら、setUserObject() を自分で呼ぶ代わりに initPlugin() に platform だけを渡して、ショップのログイン状態を読み取らせることができます。ステップ 2 の代替であり、ステップ 2 に追加する作業ではありません。
userObject・userJWT がない場合にのみプラットフォーム自動連携を試みます。initPlugin() にユーザー情報を一緒に渡していれば、そちらが使われて platform は無視されます。どちらか一方だけを使ってください。canBid がオンになります
プラットフォーム自動連携で作られたユーザー情報には canBid: true が常に付きます。つまりショップにログインしている人なら誰でもオークションに入札できます。会員ランクや購入履歴などで入札資格を絞る必要がある場合は、自動連携ではなくステップ 2 のように setUserObject() を直接呼んで canBid を計算して渡すか、CAN_BID_REQUIRED で入札時点に判断してください。platform の値 | どうやって読み取るか | ページに用意するもの |
|---|---|---|
'CAFE24' | Cafe24 スキンのログイン状態モジュールが描画する会員情報を読みます。値が遅れて入るスキンでは、入るまで待ってから連携します | スキンにログイン状態モジュールがなければ下の A を追加します |
'WISA' · 'GODOMALL' | ページ上の決められた id の要素から会員情報を読みます | 下の B の 2 つの要素を自分で出力する必要があります |
'SHOPIFY' | 同じ方式で読み取り、さらにプレイヤー内のカート機能が有効になります | B + カート連携(付録 A · カートに入れる) |
いずれの場合も、どのページから入ってもログイン状態を拾えるよう共通レイアウト(全ページが共有するヘッダー領域)に入れるのが確実です。
<!-- 1. SDK の読み込み -->
<script src="https://static.shoplive.cloud/shoplive.js"></script>
<!-- A. Cafe24 — スキンにログイン状態モジュールがない場合のみ追加します。
{$id} {$name} は Cafe24 がログイン会員の ID・名前に置き換えます。
このモジュールが描画されると .xans-member-var-id / .xans-member-var-name が作られ、
SDK はその 2 つのクラスを探して読み取ります -->
<div module="Layout_stateLogon" style="display:none;">{$id} {$name}</div>
<!-- B. WISA · ゴドモール · Shopify — 会員情報をこの id で出力します。
波かっこの中はショップ ソリューションが提供する会員変数に置き換えてください
· ゴドモール : {=gSess.memId} / {=gSess.memNm}
· WISA : {{$회원아이디}} / {{$회원명}}
未ログイン時は値が空になるのでゲストとして動作します -->
<div style="display:none;">
<span id="cloud-shoplive-user-id">MEMBER_ID</span>
<span id="cloud-shoplive-user-name">NICKNAME</span>
</div>
<script>
// 2. platform だけを渡します — setUserObject は呼びません
cloud.shoplive.initPlugin({
accessKey: 'YOUR_ACCESS_KEY',
platform: 'CAFE24' // 'CAFE24' | 'WISA' | 'GODOMALL' | 'SHOPIFY'
});
</script>
visibility: hidden で隠すと値が空になります
会員情報の要素を画面に見せない場合、display: none や画面外へ追い出す方法は値の読み取りに問題ありませんが、visibility: hidden は空文字列として読まれてゲストになります。また Cafe24 以外は初期化時に一度だけ読むので、会員情報をスクリプトで後から埋める場合は initPlugin() をそのあとに呼んでください。連携できたか確かめるには。ログイン状態で配信に入り、チャットに表示される名前を見てください。Cafe24 で会員情報の領域(.xans-member-var-id・.xans-member-var-name)が見つからない場合はコンソールに Failed - Get Cafe24 account が出ます。ほかのプラットフォームは要素がなければ静かにゲストのままです。自動連携が難しければ、ステップ 2 のように setUserObject() を直接呼べば大丈夫です。
各ショップの管理画面でコードをどこに入れるかは、付録 G · ショッププラットフォーム別の設置場所をご覧ください。
ステップ 4 · ID のハッシュ化 — 会員 ID の原文を渡さない
社内の会員 ID をそのまま渡したくない場合は、自社サーバーでハッシュ化した値を userId として使えます。マスキングと違い、Shoplive は元の ID を知ることができませんが、自社は同じハッシュ処理(同じアルゴリズム・ソルト)で同じ値を再計算し、元のユーザーに対応付けられます。同じユーザーが常に同じ値になるよう(統計・再訪の識別のため)一貫した方式で処理してください。
// Node.js — 自社サーバーでハッシュ化します(salt・アルゴリズムは常に同じに)
const crypto = require('crypto');
function hashUserId(raw) {
return crypto.createHash('sha256')
.update(raw + 'YOUR_SALT')
.digest('hex');
}
const userId = hashUserId('MEMBER_ID'); // userObject.userId または JWT の userId に使います
setUserJWT())を使用してください。salt のポリシーは Shoplive チームと合意した値を推奨します。ステップ 5 · JWT 認証用のトークンを作る(自社バックエンド)
JWT 認証に使う JWT は、Shoplive が発行した Secret Key で自社のバックエンドが署名します。ページはバックエンドから受け取った JWT を initPlugin({ userJWT }) または setUserJWT() に渡すだけです(方法 B は tk パラメータ)。
- Shoplive の担当者から Secret Key を受け取ります — base64 でエンコードされた文字列です
- ログインしたユーザー情報で下記の payload を作り、HS256 で署名します
- ページから要求されるたびに(
setUserJWT()を呼ぶ直前ごとに)JWT を新しく発行して返します。ブラウザに JWT を保存して使い回さないでください
exp まで使えてしまいます。ページを開くたびに、または setUserJWT() を呼ぶたびに、バックエンドから新しい JWT を受け取るようにしてください。userName ではなく name で、有効期限 exp が必須です。exp は JWT ライブラリが提供する期限設定 API(下の例の setExpiration・expiresIn)で指定してください — ライブラリが exp を埋めてくれます。| claim | 必須 | 説明 | 例 |
|---|---|---|---|
exp | 必須 | 有効期限(Unix 秒)。ライブラリの期限設定で埋めます | 1516239022 |
userId | 必須 | ログインユーザーの一意性を保証できる値。ハッシュ値でも構いません(ステップ 4)。空ならゲスト扱い | MEMBER_ID |
iat | 任意 | 発行時刻(Unix 秒) | 1516195822 |
name | 任意 | チャットに表示される名前(簡易認証の userName に対応)。禁止語は * に置き換えて表示 | NICKNAME |
gender | 任意 | 性別 — m · f · 空(未指定) | f |
age | 任意 | 年齢。統計では 5 歳単位でまとめて表示されます | 27 |
userScore | 任意 | ユーザーランク(-100〜100)。抽選対象の制限などの基準 | 10 |
userType | 任意 | 入場制限(Entry Type)設定時に参照される値 | VIP |
profile | 任意 | チャット一覧のプロフィール画像 URL、推奨 64x64px | https://…/profile.png |
custom | 任意 | 自由形式のデータ、最大 1KB | {"grade":"vip"} |
canBid | 任意 | true / false。オークションの入札資格(付録 A · オークション) | true |
署名する
署名の例です。2 つのコードは同じトークンを作ります — Secret Key が base64 文字列のため、ライブラリによってそのまま渡すかデコードして渡すかが異なる点だけ注意してください。
// Java — jjwt。signWith が base64 文字列を自動でデコードします
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
String base64EncodedSecretKey = "YOUR_BASE64_SECRET_KEY"; // Shoplive 担当者から受け取った値
long expiration = System.currentTimeMillis() + 12 * 60 * 60 * 1000L; // 12 時間
String jwt = Jwts.builder()
.signWith(SignatureAlgorithm.HS256, base64EncodedSecretKey)
.setExpiration(new Date(expiration))
.setIssuedAt(new Date())
.claim("userId", "MEMBER_ID") // 必須
.claim("name", "NICKNAME") // 任意 — チャットの表示名
.claim("userScore", 10) // 任意
.claim("userType", "VIP") // 任意
.compact();
// Node.js — jsonwebtoken。secretKey を自分でデコードして渡す必要があります
const jwt = require('jsonwebtoken');
const base64EncodedSecretKey = 'YOUR_BASE64_SECRET_KEY'; // Shoplive 担当者から受け取った値
const secret = Buffer.from(base64EncodedSecretKey, 'base64'); // ← デコードが必要
const token = jwt.sign(
{
userId: 'MEMBER_ID', // 必須
name: 'NICKNAME', // 任意 — チャットの表示名
userScore: 10, // 任意
userType: 'VIP' // 任意
},
secret,
{ algorithm: 'HS256', expiresIn: '12h' }
);
userId・userScore で他のユーザーになりすましたトークンを作れてしまいます。ブラウザにバンドルされるコードや公開リポジトリには置かず、必ず自社サーバーでのみ署名し、完成したトークンだけをフロントへ渡してください。簡易認証(setUserObject())は署名がないため、権限の検証には使えません。ゲストも区別する必要があるなら — ゲスト uid を受け取る 任意
ユーザー情報を渡していないゲストの視聴者には、プレイヤーが任意の識別子 uid を発行します。この値を自社側でも把握したい場合 — 未ログイン視聴者のクーポン発行履歴をまとめる、自社ログを Shoplive の統計と突き合わせるなど — は、messageCallback に ON_UID_ISSUED を登録します。プレイヤーがサーバーに接続するたびに届きます。
const messageCallback = {
ON_UID_ISSUED: function (payload) {
// payload.uid — プレイヤーが発行したゲスト識別子 · payload.campaignKey — どの配信か
const stored = localStorage.getItem('shoplive_uid');
if (stored !== payload.uid) {
localStorage.setItem('shoplive_uid', payload.uid);
}
}
};
cloud.shoplive.initPlugin({ accessKey: 'YOUR_ACCESS_KEY', messageCallback });
- ログイン済みの視聴者は
userIdで識別されます。 このイベントはログインの有無にかかわらず届きますが、ユーザー情報を渡した視聴者については渡したuserIdを基準にし、uidはゲストにのみ使ってください。 - 値は変わることがあります。 プレイヤーはゲストの
uidをブラウザに 2 時間保持し、その後に再び訪れると新しい値を発行します。ブラウザのストレージを消したり別のブラウザから入ったりしても変わります。届くたびに保存済みの値と比較して更新してください。
完了の確認
- ログイン後にチャットを送信すると、指定したユーザー名(会員名)が表示される
- (入場制限を設定した場合)
userScore/userTypeの基準に合うユーザーだけが入場できる - ログアウト →
cloud.shoplive.logout()でユーザー情報をリセットしたあとはゲストとして視聴される
前へ ← ミッション 1 · 配信を表示する次へ → ミッション 3 · ユーザー操作を処理する
ミッション 3 · ユーザー操作を処理する
initPlugin() が完了 · クーポン・商品のタップを扱うなら、Admin で該当ポップアップ・商品のクリック動作を設定済みクーポン・商品・ログインのように独自のビジネスロジックが必要な操作は、ほとんど messageCallback を通じて届きます。このステップの内容が実際の連携コードの中心です。
messageCallback はページに読み込まれた SDK の initPlugin() に登録する機能です。shoplive.show のリンク(ミッション 1 方法 B)はページに SDK 自体が読み込まれないため、コールバックを登録できません。クーポン・商品タップに反応するロジックが必要なら方法 A を使ってください。initPlugin()の呼び出し時にmessageCallbackへアクション名ごとの関数を登録します。- 登録しておくと、そのアクションが起きるたびに自動で呼ばれます。
- (任意)コールバックの中で
getPlayer()を使いプレイヤー UI を更新します。
const messageCallback = {
DOWNLOAD_COUPON: function (payload) {
console.log('クーポンがタップされました。coupon code: ' + payload.coupon);
fetch('YOUR_COUPON_API')
.then(function (res) { return res.json(); })
.then(function (res) {
if (res.success) {
alert('クーポンを取得しました。');
// 応答を待つ間にプレイヤーが閉じている可能性があるのでここで取得します(ミッション 5)
const player = cloud.shoplive.getPlayer(payload.campaignKey);
if (player) player.sendMessage('removeCoupon');
} else {
alert('クーポンはすべて配布済みです。');
}
});
},
// CLICK_PRODUCT は任意 — 定義しなければデフォルト動作(新しいウィンドウで開く)がそのまま使われます。
// 同じウィンドウで遷移させたいときなど、違う動作にしたい場合だけ下のように追加してください。
// CLICK_PRODUCT: function (payload) {
// location.href = payload.url;
// },
LOGIN_REQUIRED: function (payload) {
// ゲストがログインの必要な機能にアクセスしたとき
},
};
cloud.shoplive.initPlugin({
accessKey: "YOUR_ACCESS_KEY",
messageCallback
});
fetch('YOUR_COUPON_API') のように、クーポンがタップされたら自社サーバーの API を呼ぶ処理は messageCallback の中に自分で書きます。主なアクション
発生タイミングの太字の番号は画面の用語ガイドの図の番号です — 視聴者が画面の何をタップしたときにそのアクションが届くのかがすぐ分かります。
| アクション | 発生タイミング | payload | 用途 |
|---|---|---|---|
DOWNLOAD_COUPON | クリック動作が「クーポンダウンロード」に設定されたポップアップのタップ ⑨ ⑩ ⑪ | campaignKey, coupon, popupResourceId, type(BANNER/COUPON/NOTICE) | 定義しないと何も起きません — クーポン発行を自社システムと連携するには必須 |
CUSTOM_ACTION | クリック動作が「カスタム」に設定されたポップアップのタップ ⑨ ⑩ ⑪ | campaignKey, id, type(BANNER/COUPON/NOTICE), payload.payload(Admin のクーポン編集画面で設定したカスタム JSON) | 標準フィールドで足りないとき、好きなデータを自由形式で載せられます |
CLICK_PRODUCT | 商品のタップ ⑥ | Goods | 定義しなければ自動で新しいウィンドウへ遷移。同じウィンドウで遷移したいときや URL パラメータを足すときに上書き |
LOGIN_REQUIRED | ゲストがログインの必要な機能にアクセス ⑦ | campaignKey | ログインページへ遷移させる処理を実装。認証方式そのものはミッション 2 を参照 |
CLICK_SHARE_BTN | 共有ボタンのタップ ⑫ | campaignKey, shareUrl, title | 登録しなければデフォルト動作(OS の共有シート、またはクリップボードへコピー)が自動で実行されます。登録するとデフォルト動作が置き換わり実行されなくなるため、ログだけ取りたい場合でも共有そのものを下のように自分で実装する必要があります |
LINK | クリック動作が「リンク」に設定されたポップアップのタップ(または商品リスト上部のリンクのタップ)⑨ ⑩ ⑪ | campaignKey, popupResourceId, type(BANNER/COUPON/NOTICE), url | 上書きしなければ同じウィンドウでの遷移がデフォルト。ただし Web PIP がオンなら、プレイヤーを表示したまま遷移します |
CLICK_BACK_BUTTON | プレイヤーの戻るボタンのタップ(ui.backButton をオンにした場合)⑫ | なし | 上書きしなければ history.back()。独自ルーターへ渡すなら上書き |
ON_CLICK_CAMPAIGN_LIST_ITEM | 配信リスト(方法 C)で配信を 1 つタップ — プレイヤーの外です | ak, campaign(Campaign) | 上書きしなければモーダル プレイヤーが開きます。独自の詳細ページへ送るときに上書き |
ON_CLICK_CLOSE_PLAYER_MODAL | モーダル プレイヤーの閉じるボタンのタップ — プレイヤーの外です | campaign(Campaign) | 上書きしなければモーダルが閉じます。閉じる前に確認ダイアログを出すなど、割り込むときに上書き |
LINK_NEW_WINDOW | クリック動作が「リンク(新しいウィンドウ)」に設定されたポップアップのタップ(または商品リスト上部のリンクのタップ)⑨ ⑩ ⑪ | campaignKey, popupResourceId, type(BANNER/COUPON/NOTICE), url | 上書きしなければ新しいウィンドウでの遷移がデフォルト |
ON_CLICK_SCHEME_BUTTON | プレイヤー内のスキームボタンのタップ — 商品を見る・追加・削除、オークション落札者の決済 ⑥ | scheme(開くアドレス), schemeType, campaignKey | 上書きしなければ scheme を新しいウィンドウで開きます。schemeType で何がタップされたかを判別して自社ロジックへ渡すときに上書き — 'GO_PRODUCT' · 'ADD_PRODUCT' · 'REMOVE_PRODUCT' · 'WINNER_CHECKOUT'(オークション落札者の決済) |
REQUEST_FULL_SCREENEXIT_FULL_SCREEN | プレイヤーから全画面への切り替え・解除が要求されたとき ① | campaignKey(解除時はなし) | 上書きしなければプレイヤーの iframe にブラウザの全画面を適用・解除します。自社のレイアウトで拡大したい場合に上書き |
payload.url にパラメータが 1 つ付きます
視聴者がブラウザ PIP の状態で遷移してきたページでは、CLICK_PRODUCT · LINK · LINK_NEW_WINDOW の payload.url の末尾に csl_bp が自動で付きます。次のページでも PIP を続けるための目印です。この URL を自社ロジックで加工する場合は、見慣れないパラメータが混ざって来ることがある点にご注意ください — 削除すると遷移先で PIP が途切れます。navigator.share(対応していれば OS の共有シート)やクリップボードへのコピーが自動で実行されます。共有されるアドレスは配信キーが付いた URL です — shareUrl(ミッション 1 の initPlugin() オプション)を指定していればそのアドレスに ?ck=、指定していなければ現在のページのアドレスに ?_sl_ck= が自動で追加されます。付くパラメータと、そのアドレスから来たときの動作はミッション 4 · 共有 URL にまとめています。shareUrl に既にあるクエリパラメータは保持されるので、utm_source などのマーケティング計測パラメータをあらかじめ付けておけます。クリップボードにコピーされた場合は、プレイヤーに 「Copy to clipboard completed.」の案内が自動で表示されます。
CLICK_SHARE_BTN を登録した瞬間、このデフォルト動作は実行されなくなります。タップのログだけを取りたい場合でも、下のように共有動作そのものを自分で実装する必要があります。
CLICK_SHARE_BTN: function (payload) {
// ログなど、必要な処理
console.log('共有がタップされました', payload.campaignKey);
// デフォルト動作を保ちたいなら自分で作り直します
// payload.shareUrl が空の場合は SDK が組み立てていたアドレスを自分で作る必要があります
if (navigator.share) {
navigator.share({ title: payload.title || '', text: '', url: payload.shareUrl });
} else if (navigator.clipboard) {
navigator.clipboard.writeText(payload.shareUrl);
}
}
バナー(⑪)・クーポン(⑨)・お知らせ(⑩)のポップアップは、Admin でポップアップごとにタップ時の動作を設定します。全体は次のとおりです。
| Admin 設定 | 開発コード | 説明 |
|---|---|---|
| クーポンダウンロード | 必要(DOWNLOAD_COUPON) | コールバック未登録では何も起きません |
| リンク(同じウィンドウ) | 任意(LINK) | コールバック未登録なら同じウィンドウでの遷移がデフォルト |
| リンク(新しいウィンドウ) | 任意(LINK_NEW_WINDOW) | コールバック未登録なら新しいウィンドウでの遷移がデフォルト |
| カスタム | 必要(CUSTOM_ACTION) | Admin で定義した任意の payload を渡します |
| 詳細ポップアップ(画像) | 不要 | messageCallback なしでプレイヤーが自前で画像を表示します |
| ボトムシートを開く | 不要 | messageCallback なしでプレイヤーが自前でボトムシートを表示します |
クリック動作を設定したのに登録したコールバックが呼ばれない場合は、上の表で「開発コード不要」の項目に設定されていないか Admin で確認してみてください。
通知だけを受け取るイベント — 置き換えるものがないもの
プレイヤーから上がってくるイベントには、どの配信で起きたことかが分かるよう payload.campaignKey が常に一緒に載ります。下の表に個別に記載していないイベントも同様です。
下のイベントには SDK のデフォルト動作がありません。登録しても何かを置き換えることはなく、ただ「こういうことが起きた」と知らせるだけです。アナリティクスの送信や、自社画面の状態を合わせるのに使います。
ON_PLUGIN_INITIALIZED の liveMiniPreview は、Admin に設定された値に SDK のデフォルト値(位置 BOTTOM_RIGHT · 余白 16 · 表示時間 300)を埋めた最終結果です。ミニプレビューの位置に合わせて自社 UI をずらす必要があるときは、この値を読んでください。
| イベント | 発生タイミング | payload |
|---|---|---|
ON_PLUGIN_INITIALIZED | initPlugin() が完全に終わったとき。初期化前に先に呼んだ関数がすべて実行されたあとに届きます | liveMiniPreview — ミニプレビューの実際に適用された設定(position · marginTop · marginRight · marginBottom · marginLeft · dismissPreviewDuration) |
ON_PLAYER_STARTED | 視聴者がプレイヤーに入り再生が始まったとき | accessKey · campaignKey · isPreview(プレビュー時のみ) |
NOW_ONAIR_CHECKED | 配信中のものがあるか確認できた時点 | campaignKey · campaignStatus · title · startedAt · tags |
ON_CAMPAIGN_STATUS_CHANGED | プレイヤーが再生中の配信のステータスが変わったとき — 配信の開始・終了はここに届きます。プレイヤーが開いたときに現在のステータスで一度届き、その後は変わるたびに届きます | status('READY' · 'ONAIR' · 'CLOSED' など)· campaignKey |
ON_CHANGED_VIEWER_STAT | 視聴者数・いいね数が更新されたとき(配信中は随時) | viewerCount · likeCount · campaignKey |
ON_PLAYER_MODAL_SHOWNON_PLAYER_MODAL_HIDDEN | モーダル プレイヤーが表示・非表示になったとき | campaign(Campaign) |
ON_LIVE_MINI_PREVIEW_SHOWNON_LIVE_MINI_PREVIEW_HIDDEN | ミニプレビュー バナーが表示・非表示になったとき | なし |
ON_CLICK_CLOSE_LIVE_MINI_PREVIEW | 視聴者がミニプレビューの閉じるボタンを押したとき | campaign(Campaign) |
ON_PRODUCT_LIST_SHOWN | 商品リストのポップアップが開いたとき | productList — Goods の配列 |
ON_CHANGED_CAMPAIGN_PRODUCT_LIST | 配信に紐づく商品リストが変わったとき — 運営者が配信中に商品を追加・削除すると届きます | productList · campaignKey |
ON_RECEIVED_CHAT | 新しいチャットが届いたとき。一度に複数がまとめて届きます | chatList(配列)· campaignKey |
ON_ERASED_CHAT | 運営者がチャットを削除したとき。独自のチャット一覧を作っている場合はこのタイミングで消します | lid(削除されたチャットの id)· campaignKey |
ON_CHAT_INPUT_FOCUS_INON_CHAT_INPUT_FOCUS_OUT | 視聴者がチャット入力欄にフォーカスを入れた・外したとき。モバイルではキーボードが上がるタイミングです — 下の CHAT_READY を参照 | campaignKey |
ON_FILTERED_CHAT | chatFilterPatterns に該当してチャットが送信されなかったとき | message · regExp(一致したパターン) |
ON_UID_ISSUED | プレイヤーがサーバーに接続し、視聴者の識別子が決まったとき。ゲストの識別に使う方法はミッション 2 · ゲスト uid を受け取る | uid · campaignKey |
const messageCallback = {
ON_PLAYER_STARTED: function (payload) {
analytics.track('live_player_started', { campaignKey: payload.campaignKey });
},
ON_PLAYER_MODAL_HIDDEN: function (payload) {
// モーダルが閉じたので自社ページの状態を戻す
document.body.classList.remove('live-open');
}
};
cloud.shoplive.initPlugin({ accessKey: 'YOUR_ACCESS_KEY', messageCallback });
CHAT_READY クラスが付きます
視聴者がチャット入力欄にフォーカスを入れると、SDK が自社で作ったプレイヤーの div に CHAT_READY クラスを付け、フォーカスが外れると外します。モバイルでキーボードがプレイヤーを覆うとき、コールバックを登録せず CSS だけでレイアウトを変えられます。
/* チャット入力中は下の領域をたたんでおく */
#shoplive-player.CHAT_READY ~ .my-product-section {
display: none;
}
Goods payload の構造(CLICK_PRODUCT)
| フィールド | 説明 |
|---|---|
sku | 商品コード |
name | 商品名 |
brand | ブランド |
url | 商品詳細ページの URL — 定義しなければこの値で新しいウィンドウへ遷移 |
goodsId | 商品の識別子 |
campaignId | 配信の識別子 |
description | 商品説明 |
showingNow | NOW マークの表示有無 |
salesStatus | ON_SALE / SOLDOUT / ALMOST_SOLDOUT |
originalPrice | 販売価格 |
discountedPrice | 割引価格 |
discountPercentage | 割引率 |
currency | 通貨(例: KRW) |
isCartOn | カートに入っているか |
カートに入れる(CLICK_PRODUCT_CART)アクションも同じ Goods 構造を payload として使います。
CLICK_PRODUCT_CART アクション(payload: Goods)でカートボタンのタップを処理できます。Campaign payload の構造(配信情報)
配信リストのタップ・モーダルの表示・ミニプレビューなど配信単位で発生するイベントは、配信情報を一緒に渡します。次の 6 つは常に含まれます。
| フィールド | 説明 |
|---|---|
campaignKey | 配信の固有キー — setPlayer・showFeaturedPlayerModal にそのまま渡せます |
campaignStatus | 'READY'(予定)· 'ONAIR'(配信中)· 'CLOSED'(終了) |
title | 配信タイトル |
scheduledAt | 配信予定時刻(ミリ秒の timestamp) |
startedAt | 実際の開始時刻。開始前は null |
endedAt | 実際の終了時刻。終了前は null |
イベントによっては tags・memo・backgroundUrl などが追加で載ることもあります。上の 6 つ以外のフィールドはイベントごとに異なるので、実際に使う前に console.log(payload) で確認してください。
ユーザー行動のログ(任意)
いいね・共有・チャット送信など、プレイヤー内の UI タップを自社で追跡したい場合は EVENT_LOG アクションを登録します。上で扱ったアクションと違い、処理すべきビジネスロジックがない純粋なログ用途なので、別途の有効化依頼なしにすぐ使えます。
EVENT_LOG: function (payload) {
console.log(payload.name, payload.feature, payload.parameter);
// 例: payload.name が 'like_button', 'share_button', 'chat_send_button', 'coupon' など
}
| フィールド | 説明 |
|---|---|
name | イベント名(ボタン・アクションごとに異なります) |
feature | "click" / "action" / "show" |
parameter | イベントごとの参照情報(ある場合) |
campaignKey | 配信の識別子 |
追跡できるイベント名
payload.feature で性格が分かれます — click は視聴者が直接押したもの、show は画面に現れたもの、action はそれ以外の動作です。
feature | イベント名 |
|---|---|
click | back_button · option_button · share_button · pip_button · like_button · chat_button · chat_send_button · mute_button · unmute_button · hide_controls · show_controls · video_expand_button · video_contract_button · landscape_button · portrait_button · coupon · notice · banner · product_list_button · product_list_item · product_list_banner · product_buy_button · product_add_to_watchlist · product_remove_from_watchlist · brand_favorite_button · benefit_button · benefit_contents · qna_list_button · qna_list_faq_tab · qna_list_all_answer_tab · qna_list_my_answer_tab · qna_chat_card · video_display_resolution_change · video_display_resolution_close · edit_nickname_close_button · edit_nickname_clear_button · edit_nickname_save_button · replay_play_button · replay_pause_button |
show | player_on_foreground · player_on_background · player_active_seconds · product_list_banner · show_qna_chat_card · quiz_question_show · quiz_answer_show |
action | product_list_show · product_list_hide · product_list_expand · quiz_select · replay_seek · redirect_campaign |
配信にクーポン・クイズ・Q&A などがなければ、該当するイベントは発生しません。一覧にない名前が届いた場合は新しく追加されたものなので、payload をそのまま渡して記録しておけば大丈夫です。
視聴時間を計る
プレイヤーがアクティブな間、player_active_seconds が3 秒間隔で届きます。累計視聴時間は parameter.activatedDuration に計算済みで届くので、自分で足し合わせる必要はありません。
parameter フィールド | 説明 |
|---|---|
activatedDuration | 累計視聴時間(ミリ秒)。タブが隠れていた区間は除かれています |
interval | 直前の報告からの経過時間(ミリ秒) |
activatedAt | 視聴を開始した時刻(ミリ秒の timestamp) |
videoCurrentTime | 映像の再生位置(秒)。アーカイブのどこを見ているか |
mode | 'LIVE' · 'REPLAY'(アーカイブ)· 'PREVIEW'(プレビュー)— ライブとアーカイブの視聴時間を分けて集計するときに使います |
EVENT_LOG: function (payload) {
if (payload.name === 'player_active_seconds') {
const p = payload.parameter;
// 累計視聴時間は SDK が計算して送ってくれます(ミリ秒)
analytics.track('live_watch', {
campaignKey: payload.campaignKey,
mode: p.mode, // LIVE / REPLAY / PREVIEW
seconds: Math.floor(p.activatedDuration / 1000)
});
}
}
累計は配信中(ONAIR)で、かつタブが画面に見えているときに進みます。タブが隠れていた区間は activatedDuration に含まれないので、player_on_foreground / player_on_background で別途ふるい分ける必要はありません。
完了の確認
- クーポンをタップすると、登録したコールバックが呼ばれる
- 商品をタップすると、payload で商品情報が届く
- ゲストがチャットなどログインの必要な機能をタップすると
LOGIN_REQUIREDが呼ばれる
ミッション 4 · 他のページでも配信を知らせる
ミッション 1 が「配信をどこに描くか」だったのに対し、このミッションはどうやってそのページへ来てもらうかです。手段は 3 つあり、互いに独立しているので必要なものだけ使ってください。
ミニプレビュー — 配信中の番組を他のページの隅に表示する
配信中のものがあると、配信ページ以外のページの隅に小さなバナーが出て配信をプレビューします。視聴者がタップするとモーダル プレイヤーへそのまま繋がります。
別途の呼び出しは不要です。プレビューを出したいページに initPlugin() を入れておけば、配信中のものがあるときに自動で表示されます。そのため通常は共通レイアウトに初期化コードを一度入れるだけで済みます。
<!-- 共通レイアウト(全ページが共有する head 領域)に一度だけ -->
<script src="https://static.shoplive.cloud/shoplive.js"></script>
<script>
cloud.shoplive.initPlugin({ accessKey: 'YOUR_ACCESS_KEY' });
</script>
いつ出て、いつ出ないか
原理は 1 つです — 視聴者がすでに配信を見ているページには出ません。配信へ連れてくるのが目的なのに既に来ているので出す理由がなく、画面を覆うだけです。残りは重複表示を防ぐための条件です。
| こういうときは出ません | 理由 |
|---|---|
同じページに setPlayer のプレイヤーが表示されているとき | すでに配信を見ている画面です。プレイヤーが閉じれば再び出ます |
| モーダル プレイヤーが開いているとき | |
setOverall のメイン配信領域が生きているとき | |
ページが iframe の中で開かれたとき | コンソールに Disabled mini preview in iframe が出ます |
| ブラウザ PIP から来たページのとき | アドレスに csl_bp があれば既に PIP で視聴中なのでスキップします(ミッション 3) |
| 視聴者が閉じたあと、猶予時間の中にあるとき | すぐ下の閉じたあとどのくらい出ないかを参照 |
sl_p.close_clicked_timestamp)に記録され、Admin に設定された猶予時間(秒)のあいだ再表示されません。この値が設定されていない場合は猶予ではなくブロックです — そのセッション中は二度と出ません。猶予時間を設けたい場合は Shoplive 担当者へ設定をご依頼ください。
同じタイムスタンプはモーダル プレイヤーを閉じたときにも記録されます。そのため視聴者が配信を見て閉じると、ミニプレビューも一緒に静かになります。
開発中にもう一度見たい場合は、ブラウザの開発者ツールのセッション ストレージから上のキーを削除してください。
自分で表示・非表示にする 任意
自動で出るのを避け、自社が決めたタイミングだけ表示したい場合は、初期化で自動表示をオフにして自分で呼び出します。
// 初期化時に自動表示をオフにする
cloud.shoplive.initPlugin({
accessKey: 'YOUR_ACCESS_KEY',
useAutoPreview: false
});
// 好きなタイミングで
cloud.shoplive.showLiveMiniPreview(); // 表示
cloud.shoplive.dismissLiveMiniPreview(); // 非表示
自動表示をオフにしても上のブロック条件はそのまま適用されます — showLiveMiniPreview() を直接呼んでも、iframe の中だったり猶予時間中だったりすれば何も起きません。
タップ時の動作を変える 任意
デフォルト動作はモーダル プレイヤーを開くことです。独自のライブページへ送りたい場合は下のように割り込みます。
cloud.shoplive.setOnClickLiveMiniPreview(function (campaign) {
// campaign には campaignKey · title · campaignStatus などが入っています
location.href = '/live?ck=' + campaign.campaignKey;
});
バナーが表示・非表示・クローズされる瞬間は通知イベント(ON_LIVE_MINI_PREVIEW_SHOWN · ON_LIVE_MINI_PREVIEW_HIDDEN · ON_CLICK_CLOSE_LIVE_MINI_PREVIEW)で分かります。
位置とサイズ
どちらも自社コードでは変更しません — 位置と余白は Shoplive Admin の設定で、サイズは画面幅で決まります。周囲の UI をずらすときの参考にしてください。
位置
| 項目 | どう決まるか |
|---|---|
| デフォルトの位置 | Admin の position — デフォルト値は右下(BOTTOM_RIGHT) |
| 画面端からの余白 | Admin の marginTop · marginRight · marginBottom · marginLeft — デフォルト値はそれぞれ 16(px) |
| 視聴者が動かす | ドラッグで動かせます。動かした位置はセッション ストレージ(cslltposclnm)に記憶され、ページを移動しても保持されます。Admin 設定でドラッグを禁止することもできます |
いま適用されている値は ON_PLUGIN_INITIALIZED イベントで読み取れます — ミニプレビューが出る位置を避けて自社 UI(フローティングボタンなど)を配置するときに使います。ただし視聴者がドラッグで動かしたあとは実際の位置が変わります。
サイズ
| 配信の形 | 画面幅 | 幅 | 高さ |
|---|---|---|---|
| 縦型(9:15) | 1025px 以上 | 17vw | 17vw × 15/9(幅の約 1.67 倍) |
| 481 〜 1024px | 26vw | 26vw × 15/9 | |
| 480px 以下 | 35vw | 35vw × 6/4(幅の 1.5 倍) | |
| 横型(15:9) | すべての幅 | 26vw | 26vw × 9/15 |
| 配信の形 | 最小 | 最大 |
|---|---|---|
| 縦型 | 100 × 150px | 200 × 332px |
| 横型 | 160 × 96px | 332 × 200px |
比率は 9:16・16:9 ではなく 9:15・15:9 です。ピクセル単位で位置を合わせるときはご注意ください。
共有 URL — リンク 1 つでその配信を開く
プレイヤーの共有ボタン(ui.shareButton)が作るアドレスと、そのアドレスから来たときの動作です。shareUrl を指定したかどうかで、付くパラメータとその後の動作が変わりますので、2 つを分けてご覧ください。
initPlugin の設定 | 共有されるアドレス | そのアドレスから来ると |
|---|---|---|
shareUrl 未指定(デフォルト) | 現在のページのアドレス + ?_sl_ck={campaignKey} | 同じページに setOverall があれば、SDK がこの値を読んでモーダル プレイヤーを自動で開きます |
shareUrl: 'https://my-shop.com/live' | 指定したアドレス + ?ck={campaignKey} | 自動では開きません。自社コードで ck を読み、自分でプレイヤーを表示する必要があります |
// shareUrl を指定した場合 — 受け取る側で自分で開きます
const ck = new URLSearchParams(location.search).get('ck');
if (ck) {
cloud.shoplive.showFeaturedPlayerModal({ campaignKey: ck });
// または cloud.shoplive.setPlayer('shoplive-player', { campaignKey: ck });
}
_sl_ck を付け、閉じると戻します。おかげで再生中にアドレスバーをコピーして送れば、受け取った人も同じ配信が開いた状態で入ってこられますし、モバイルで戻るを押してもページを離れずモーダルだけが閉じます。独自ルーターと衝突する場合は disableHistoryHook でオフにできます。マーケティングの流入経路を残すには、共有・広告のアドレスに utm_source · utm_medium · utm_campaign · utm_content を付けてください。SDK がこの値を読み取り、視聴・コンバージョンの記録に併せて残します(ミッション 6)。
utm_source がない場合は広告 ID のパラメータが代わりに使われます — adid · adId · adld · adLd · ad-ld · ad-id · ad-Id のうち最初に見つかった値です。広告プラットフォームが adid で送ってくる場合は、アドレスを直さなくてもそのまま拾われます。
配信カード · 配信中カバー 任意
リスト全体(方法 C)までは要らず、特定の配信 1 つだけ、あるいは配信中のときだけ何かを見せたいときに使います。
| 関数 | 何が描かれるか |
|---|---|
setLivePreview(containerId, { campaignKey, onClick }) | 指定した配信のプレビューカード。配信中なら映像が、終了していればポスター画像が出ます。onClick を渡すとタップ時にその関数が実行されます |
destroyLivePreview(containerId?) | 上のカードを削除します。引数を省略するとページ上のすべてのカード |
setOnAirCover(containerId) | 配信中のものがあるときだけその領域にカバーが現れます。なければ何も描きません |
setLandscapeOnAirCover(containerId) | 上と同じで横型配信向けのカバー |
<div id="live-card"></div>
<script>
cloud.shoplive.setLivePreview('live-card', {
campaignKey: 'YOUR_CAMPAIGN_KEY',
onClick: function (campaign) {
cloud.shoplive.showFeaturedPlayerModal({ campaignKey: campaign.campaignKey });
}
});
</script>
<div id="on-air-cover"></div>
<script>
cloud.shoplive.setOnAirCover('on-air-cover');
</script>
カバーが実際に表示されたかは ON_ONAIR_COVER_SHOWN イベントの payload.show で分かります — 配信がなくカバーが出ないときに、その場所を別のバナーで埋めるといった使い方ができます。
完了の確認
- 配信中のとき、初期化コードを入れた他のページの隅にミニプレビューが出る
- ミニプレビューをタップするとモーダル プレイヤーが開く(または自社が指定した動作が実行される)
- 再生中にアドレスバーをコピーして新しいタブに貼ると、同じ配信が開いた状態で表示される
ミッション 5 · プレイヤーを制御する 任意
ミッション 3 が「プレイヤーからの知らせを受け取る」側だとすれば、このミッションはその逆方向です。プレイヤーのオブジェクトを取得して命令を送ります。
SDK の読み込みから命令の送信までを 1 ページにまとめると次のようになります。1 · 2 · 4 は ミッション 1 方法 A そのままで、このミッションが加えるのは 3 と 5 です。
<!-- 1. SDK の読み込み -->
<script src="https://static.shoplive.cloud/shoplive.js"></script>
<!-- 2. プレイヤーが入る場所 -->
<div id="shoplive-player"></div>
<!-- 3.(任意)プレイヤーを操作する自社 UI — ここではプレイヤー外のミュートボタン -->
<button type="button" id="mute-btn">ミュート</button>
<script>
// 4. 初期化してプレイヤーを表示します(ミッション 1)
cloud.shoplive.initPlugin({ accessKey: 'YOUR_ACCESS_KEY' });
cloud.shoplive.setPlayer('shoplive-player', { campaignKey: 'YOUR_CAMPAIGN_KEY' });
// 5.(任意)命令を送ります — ここでは外のボタンが押されたとき
document.getElementById('mute-btn').addEventListener('click', function () {
const player = cloud.shoplive.getPlayer('YOUR_CAMPAIGN_KEY');
if (!player) return; // まだ表示されていなければ何もしません
player.sendMessage('mute');
});
</script>
3 · 5 はこの例で選んだ 1 つの方式にすぎません。プレイヤーの外にボタンを置いて押したらミュートする形を示しましたが、命令を送るタイミングは何でも構いません — 自社ページの別の UI、スクロールやタイマーなどの独自ロジック、あるいは ミッション 3 のコールバックの中など、どこからでも getPlayer() で取得して送れます。プレイヤーをただ表示するだけなら、このミッション自体が不要です。
setPlayer() のすぐ次の行で getPlayer() を呼ぶと undefined です
initPlugin() はサーバーから設定を取得する非同期の処理で、その間 setPlayer() はキューに入って後から実行されます。そのためすぐ次の行にはまだプレイヤーが存在しません。
上の例のように視聴者がボタンを押すタイミングで取得するのが一番簡単です。ページが開いてすぐ何かを送る必要があるなら、再生が始まった通知を受け取ってから取得してください。
cloud.shoplive.initPlugin({
accessKey: 'YOUR_ACCESS_KEY',
messageCallback: {
// 再生が始まった直後 — この時点ではプレイヤーが必ず存在します
ON_PLAYER_STARTED: function (payload) {
const player = cloud.shoplive.getPlayer(payload.campaignKey);
if (player) player.sendMessage('hideControls');
}
}
});
cloud.shoplive.setPlayer('shoplive-player', { campaignKey: 'YOUR_CAMPAIGN_KEY' });
プレイヤーを取得する
| 呼び出し | 何が返るか |
|---|---|
getPlayer() | いまアクティブなプレイヤーを 1 つ。配信中(ONAIR)のものがあればそれを優先し、なければ最後に作られたプレイヤーを返します |
getPlayer('CAMPAIGN_KEY') | その配信のプレイヤー。playerAlias を指定していれば別名でも探せます |
getActivePlayers() | いま生きているプレイヤーの配列。1 ページに複数表示しているとき、すべてを巡回するのに使います |
undefined です
まだ setPlayer が実行される前や、すべて片付けられたあとは getPlayer() は何も返しません。messageCallback が呼ばれる瞬間はプレイヤーが表示されている時点なので安全ですが、その中で fetch などを待ったあとは話が別です — 待っている間に視聴者がモーダルを閉じたかもしれません。非同期の待機のあとはプレイヤーを取り直し、if (player) で確認してください。プレイヤーのオブジェクトから直接読める値は次のとおりです。
| プロパティ | 説明 |
|---|---|
campaignKey | このプレイヤーが再生している配信のキー |
campaignStatus | 'READY' · 'ONAIR' · 'CLOSED' — リアルタイムで更新されます |
playerAlias | 指定していればその別名 |
container | プレイヤーが入っている、自社が作った div 要素 |
送れるコマンド
player.sendMessage(コマンド, payload) の形です。以下は自社連携で使うものです。
| コマンド | payload | 動作 |
|---|---|---|
removeCoupon | なし | 画面に出ているクーポン ポップアップを消します。クーポン発行の処理を終えたあとに呼ぶのが一般的です |
removeBanner · removeNotice | なし | バナー · お知らせのポップアップを消します |
mute · unmute | なし | ミュートのオン · オフ |
playVideo · pauseVideo | なし | 再生 · 一時停止 |
videoRefresh | なし | 映像を読み込み直します。ネットワークが切れて復帰したあとの回復用 |
hideControls · showControls | なし | コントロール UI の非表示 · 表示 |
dismissGoodsList | なし | 開いている商品リストのポップアップを閉じます |
GET_CURRENT_PLAYBACK_TIME | なし | 現在の再生位置を問い合わせます。答えはすぐには返らず CURRENT_PLAYBACK_TIME イベントで戻ってきます — 下を参照 |
showDialog | { title, message }任意: cancelText · confirmText · confirmTextColor · confirmBackgroundColor | プレイヤーの上にダイアログを出します。confirmText を渡すと確認 · キャンセルの 2 ボタンになり、渡さなければ閉じるボタン 1 つだけになります。title は空にすると省略されます |
showToast | { message }任意: duration · position | 短いトーストを表示します。duration はミリ秒で、0 なら自分で消すまで残ります。position はデフォルト 'BOTTOM' |
GET_CURRENT_PLAYBACK_TIME は問い合わせて答えを受け取る唯一のコマンドです。答えは messageCallback の CURRENT_PLAYBACK_TIME に届きます。
// 1) 問い合わせる
cloud.shoplive.getPlayer(PAGE_CAMPAIGN_KEY).sendMessage('GET_CURRENT_PLAYBACK_TIME');
// 2) 答えを受け取る
const messageCallback = {
CURRENT_PLAYBACK_TIME: function (payload) {
payload.playbackTimeInSeconds; // 132.4 (数値、秒)
payload.playbackTime; // '00:02:12' (HH:mm:ss の文字列)
},
};
ライブなら配信開始時刻からの経過時間、アーカイブなら映像の現在の再生位置です。配信開始時刻がまだ分からない場合は 0 が返ります。
const messageCallback = {
DOWNLOAD_COUPON: function (payload) {
fetch('YOUR_COUPON_API', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ coupon: payload.coupon })
})
.then(function (res) { return res.json(); })
.then(function (res) {
// 応答を待つ間にプレイヤーが閉じている可能性があるので、ここで取り直します
const player = cloud.shoplive.getPlayer(payload.campaignKey);
if (!player) return;
if (res.success) {
player.sendMessage('showDialog', {
title: 'クーポン発行完了',
message: 'クーポン番号 ' + payload.coupon + ' が発行されました。'
});
player.sendMessage('removeCoupon'); // 受け取ったクーポンは画面から片付ける
} else {
player.sendMessage('showToast', { message: 'クーポンはすべて配布済みです。' });
}
})
.catch(function () {
const player = cloud.shoplive.getPlayer(payload.campaignKey);
// 失敗したときに何もしないと、視聴者には押しても反応がないように感じられます
if (player) player.sendMessage('showToast', { message: 'しばらくしてからもう一度お試しください。' });
});
}
};
cloud.shoplive.initPlugin({ accessKey: 'YOUR_ACCESS_KEY', messageCallback });
上の例で押さえておきたい点が 2 つあります。
getPlayer()ではなくgetPlayer(payload.campaignKey)です。引数なしで呼ぶと配信中(ONAIR)のものが優先されるため、1 ページにプレイヤーが複数あるときクーポンをタップしたのとは別のプレイヤーにダイアログが出ることがあります。イベントの payload にcampaignKeyが入っているので、そのまま渡せば大丈夫です。- プレイヤーは
await/thenのあとに取り直します。サーバーの応答を待つ間に視聴者がモーダルを閉じると、そのプレイヤーは消えています。コールバックの先頭で掴んだオブジェクトにメッセージを送っても、どこにも届きません。
上の表にないコマンド名をコードで見かけた場合は、モバイル SDK の WebView や Shoplive の運用ツールが使う内部コマンドです。Web 連携では使いません。
完了の確認
getPlayer()がプレイヤーのオブジェクトを返し、campaignKeyが表示した配信と一致する- クーポンのタップ後に
removeCouponを送るとクーポン ポップアップが消える showDialogで送ったダイアログがプレイヤーの上に表示される
ミッション 6 · 計測 — 流入と購入
userId視聴者が商品をタップして商品ページへ移動した瞬間、SDK の追跡は終わります。そのあと決済が成立したかは自社のページでしか分からないので、購入完了の時点で一度知らせていただくことで「この配信がどれだけ売上を作ったか」が集計されます。
どこから来たか — マーケティング流入の計測
配信ページのアドレスに utm_ で始まるパラメータを付けておくと、SDK がその値を読み取りどのチャネルから来た視聴者かを併せて記録します。Instagram のバナーから来た人と、SMS から来た人の視聴・購入を分けて見られます。
| パラメータ | 何を入れるか | 例 |
|---|---|---|
utm_source | 流入チャネル | instagram |
utm_medium | メディアの種別 | banner |
utm_campaign | マーケティング キャンペーン | spring_sale |
utm_content | クリエイティブ | type2 |
4 つすべてを入れる必要はなく、必要なものだけ付ければ大丈夫です。
https://my-shop.com/live?utm_source=instagram&utm_medium=banner&utm_campaign=spring_sale
initPlugin() を呼ぶ瞬間のページアドレスから読み取ります
つまりその時点でアドレスバーにクエリが残っている必要があります。SPA でルーティングしながらクエリストリングを落としてから初期化したり、広告リンクを受けてクエリのないアドレスへリダイレクトしてからプレイヤーを表示したりすると、流入情報がまるごと消えます — エラーも出ず、ただ空の値として記録されます。ここで読み取った値は購入コンバージョンの報告にも自動で付いていきます。別途渡すものはなく、流入 → 視聴 → 購入が一本に繋がります。
集計結果は Shoplive Admin の統計で流入チャネル別に分けて見られます。
広告プラットフォームから来る場合
広告プラットフォームはリンクに独自の計測パラメータを付けて送ってきます。SDK がページのアドレスをまるごとプレイヤーまで渡すので、自社で処理することはありません — ただしそのアドレスがそのまま残っている必要があります。
- Web — 広告リンクが着地したランディングページでクエリストリングを消さないでください。リダイレクトを 1 回挟む場合は、クエリをそのまま引き継いで渡してください
- ハイブリッドアプリ(WebView) — アプリが広告リンクを受けて WebView を開くとき、クエリを WebView の URL へそのままコピーする必要があります。WebView 自体の設定は付録 D をご覧ください
- ネイティブアプリ — Web SDK ではなく iOS・Android ネイティブ SDK のディープリンク処理の領域です。Shoplive 担当者までお問い合わせください
広告 ID は adId でも受け取ります — adid · ad-id のように表記が違っても認識します。
購入コンバージョン ステップ 1 · どこに入れるか
注文が確定したあと一度だけ開かれるページ — 通常は注文完了・決済完了ページです。カートや決済の途中の画面に入れると離脱した注文まで購入として集計され、リロードで何度も開かれるページに入れると同じ注文が重複して報告されます。
購入コンバージョン ステップ 2 · 送る
SDK の読み込み → 初期化 → ユーザー情報 → 報告 の順です。初期化が終わる前に sendConversionEvent() を呼んでも SDK が待たせてから実行するので、順番が原因で失敗することはありません。
<script src="https://static.shoplive.cloud/shoplive.js"></script>
<script>
cloud.shoplive.initPlugin({ accessKey: 'YOUR_ACCESS_KEY' });
// ログインユーザーなら、視聴時と「同じ」userId を入れます(ステップ 3 参照)
cloud.shoplive.setUserObject({ userId: 'MEMBER_ID' });
cloud.shoplive.sendConversionEvent({
accessKey: 'YOUR_ACCESS_KEY', // 必須
eventType: 'purchase', // 必須 — 'purchase'(購入完了)/ 'cartIn'(カートに追加)
orderId: 'UNIQUE_ORDER_ID', // 自社の注文番号
products: [
{ productId: 'PRODUCT_ID_1', sku: 'PRODUCT_SKU_1', purchaseUnitPrice: 10000, purchaseQuantity: 1, currency: 'KRW' },
{ productId: 'PRODUCT_ID_2', sku: 'PRODUCT_SKU_2', purchaseUnitPrice: 15000, purchaseQuantity: 2, currency: 'KRW' }
]
});
</script>
| フィールド | 必須 | 説明 |
|---|---|---|
accessKey | 必須 | 初期化で渡していても、このオブジェクトにもう一度入れる必要があります — ないとコンソールに Invalid request が出るだけで送信されません |
eventType | 必須 | どのコンバージョンか — 購入完了は 'purchase'、カート追加は 'cartIn' |
orderId | 任意 | 自社の注文番号。そのまま一緒に送信されます — どの注文のコンバージョンかをあとで突き合わせたいなら入れておいてください |
products | 任意 | 購入した商品の配列 — 各項目のフィールドは下の表を参照 |
timestamp | 任意 | 購入時刻。入れなければ呼び出し時刻が使われます |
custom | 任意 | 一緒に残したい任意の値 |
userObject · userJWT | 任意 | この呼び出しだけに使うユーザー情報。入れなければ setUserObject() · setUserJWT() で渡した値が使われます |
アドレスに utm_source などの UTM パラメータがあれば、このリクエストに一緒に載って送信されます — 広告・共有の流入別にコンバージョンを分けて見たい場合は、流入アドレスに UTM を付けておいてください。
products 配列の各項目です。
| フィールド | 必須 | 説明 |
|---|---|---|
productId | 必須 | Shoplive に登録された商品 ID |
sku | 必須 | 商品コード |
purchaseUnitPrice | 必須 | 購入単価 |
purchaseQuantity | 必須 | 購入数量 |
currency | 必須 | 通貨(例: 'KRW') |
customerProductId | 任意 | 自社独自の商品 ID |
ここでの「必須」は SDK の型宣言に基づくものです。実際には accessKey と eventType だけを検査して送信するため、一部が欠けてもリクエスト自体は送られます — ただし集計から静かに漏れることがあるので、埋めて送ってください。
購入コンバージョン ステップ 3 · 視聴記録と結び付く基準
視聴記録と購入報告は別々のリクエストとして送られます。映像を 3 秒以上見た時点でプレイヤーが視聴記録を送り、購入は上の sendConversionEvent() が送ります。この 2 つをサーバーが識別子で突き合わせてコンバージョンが成立します。そのため識別子がずれていると、両方の記録が残っていてもコンバージョンとして集計されません — 次の 3 つのいずれかが一致している必要があります。
| 区分 | 結び付く基準 | 自社で合わせるもの |
|---|---|---|
| ログインユーザー | userId | 配信を見るときにミッション 2 で渡した値とまったく同じ値を注文完了ページでも渡します。ハッシュ化しているなら同じハッシュ値である必要があります |
| 未ログイン(ゲスト) | ブラウザに保存された匿名識別子 | 呼び出すものはありませんが、同じブラウザ · 同じドメインである必要があります |
| 独自の識別子がある場合 | anonId | initPlugin({ anonId }) で渡すと、ログインなしでも視聴と購入を結び付けられます。ページのアドレスに ?anonId= で渡しても認識されます |
www.shop.com で見て order.shop.com で決済)、同じ人として繋がりません。ドメインを揃えるのが難しければ、userId か anonId で結び付けるのが確実です。ショップ プラットフォームでは 任意
注文完了ページを自分で作れないプラットフォームでは、以下の場所に同じ呼び出しを入れます。注文番号と商品情報をプラットフォームが渡す値で埋める部分だけが異なります。
Cafe24
スキンの order_result.html(注文完了画面)の </body> 直前に入れます。注文番号は Cafe24 が埋める {$order_id} で受け取り、注文商品のリストは Cafe24 API で取得します。
<script src="https://static.shoplive.cloud/shoplive.js"></script>
<script>
cloud.shoplive.initPlugin({ accessKey: 'YOUR_ACCESS_KEY' });
const orderId = '{$order_id}'; // Cafe24 が実際の注文番号に置き換えます
// 会員注文なら、視聴時と同じ userId を入れます
// cloud.shoplive.setUserObject({ userId: 'MEMBER_ID' });
cloud.shoplive.sendConversionEvent({
accessKey: 'YOUR_ACCESS_KEY',
eventType: 'purchase',
orderId: orderId,
products: [
// Cafe24 API で取得した注文商品を { productId, sku, purchaseUnitPrice, purchaseQuantity, currency } の形で埋めます
]
});
</script>
注文商品を Cafe24 API(CAFE24API.getOrderDetailInfo)で取得するにはアプリキーが必要です。この値は Shoplive 担当者までお問い合わせください。
Shopify
注文完了画面にスクリプトを直接入れられないため、カスタムピクセルに登録して checkout_completed のタイミングで呼び出します。
const script = document.createElement('script');
script.src = 'https://static.shoplive.cloud/shoplive.js';
script.async = true;
document.head.appendChild(script);
script.onload = function () {
cloud.shoplive.initPlugin({ accessKey: 'YOUR_ACCESS_KEY' });
analytics.subscribe('checkout_completed', function (event) {
const checkout = event.data.checkout;
// 会員注文なら、視聴時と同じ基準で userId を入れます
const customerId = checkout.order.customer && checkout.order.customer.id;
if (customerId) {
cloud.shoplive.setUserObject({ userId: String(customerId) });
}
cloud.shoplive.sendConversionEvent({
accessKey: 'YOUR_ACCESS_KEY',
eventType: 'purchase',
orderId: checkout.order.id,
products: checkout.lineItems.map(function (item) {
return {
productId: item.variant.product.id,
sku: item.variant.sku,
purchaseUnitPrice: parseFloat(item.variant.price.amount),
purchaseQuantity: item.quantity,
currency: item.variant.price.currencyCode
};
})
});
});
};
完了の確認
- 注文完了ページで、ネットワークタブに
/conversion/eventリクエストが 1 回記録される - リロードや戻るで同じ注文が複数回報告されない
- (ログイン)リクエスト送信時の
userIdが、配信を見たときに渡した値と同じ - 集計結果は Shoplive Admin のコンバージョン レポートで確認します — 反映に時間がかかることがあります
前へ ← ミッション 5 · プレイヤーを制御する次へ → 全体のサンプル
全体のサンプル — ミッションを 1 ページにまとめる
ここまでの内容を 1 ページにまとめると次のような形になります。実際のサービスに合わせて YOUR_ACCESS_KEY、YOUR_CAMPAIGN_KEY とコールバック内のロジックを埋めるだけです。購入コンバージョン(ミッション 6)はこのページではなく注文完了ページに入るので、下に分けて置いています。
ライブページ
<script src="https://static.shoplive.cloud/shoplive.js"></script>
<script>
// ── ミッション 3 · ユーザー操作の処理
const messageCallback = {
DOWNLOAD_COUPON: function (payload) {
// 自社のクーポン発行 API を呼び、成功したときだけ画面からクーポンを片付ける(ミッション 5)
fetch('YOUR_COUPON_API', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ coupon: payload.coupon })
})
.then(function (res) { return res.json(); })
.then(function (res) {
// 応答を待つ間にプレイヤーが閉じている可能性があるのでここで取得する
const player = cloud.shoplive.getPlayer(payload.campaignKey);
if (!player) return;
if (res.success) {
player.sendMessage('removeCoupon');
} else {
player.sendMessage('showToast', { message: 'クーポンはすべて配布済みです。' });
}
});
},
LOGIN_REQUIRED: function () {
location.href = '/login?returnTo=' + encodeURIComponent(location.href);
},
ON_CLICK_CAMPAIGN_LIST_ITEM: function (payload) {
// デフォルト動作はモーダルを開くこと。独自の配信詳細ページへ送りたいときだけ上書きします
//(モーダルで開くデフォルト動作をそのまま使うなら、このコールバックは登録しないでください)
location.href = '/live/' + payload.campaign.campaignKey;
}
};
// ── ミッション 1 · 初期化(ミッション 4 · 共有 URL の指定)
cloud.shoplive.initPlugin({
accessKey: 'YOUR_ACCESS_KEY',
messageCallback: messageCallback,
shareUrl: 'https://my-shop.com/live'
});
// ── ミッション 2 · ログインユーザーなら連携(ゲストならこのブロックごとスキップ)
cloud.shoplive.setUserObject({ userId: 'YOUR_HASHED_USER_ID', userName: 'YOUR_USER_NAME' });
// このページに固定で表示する配信
const PAGE_CAMPAIGN_KEY = 'YOUR_CAMPAIGN_KEY';
</script>
<!-- ── ミッション 1 · 方法 A — 特定の配信 1 つをこの場所に -->
<div id="shoplive-player"></div>
<script>
cloud.shoplive.setPlayer('shoplive-player', {
campaignKey: PAGE_CAMPAIGN_KEY,
ui: { shareButton: true }
});
</script>
<!-- ── ミッション 1 · 方法 C — メイン配信 + リストをテンプレートで(方法 A とどちらか一方) -->
<!--
<div id="shoplive-overall-area"></div>
<script>
cloud.shoplive.setOverall('shoplive-overall-area');
</script>
-->
<!-- ── ミッション 4 · 共有リンクから来た場合はその配信を開く -->
<script>
const ck = new URLSearchParams(location.search).get('ck');
// このページに既に表示している配信ならモーダルを重ねて開かない
if (ck && ck !== PAGE_CAMPAIGN_KEY) {
cloud.shoplive.showFeaturedPlayerModal({ campaignKey: ck });
}
</script>
注文完了ページ
<script src="https://static.shoplive.cloud/shoplive.js"></script>
<script>
cloud.shoplive.initPlugin({ accessKey: 'YOUR_ACCESS_KEY' });
// 配信を見たときと「同じ」userId でなければコンバージョンに繋がりません
cloud.shoplive.setUserObject({ userId: 'YOUR_HASHED_USER_ID' });
cloud.shoplive.sendConversionEvent({
accessKey: 'YOUR_ACCESS_KEY',
eventType: 'purchase',
orderId: 'UNIQUE_ORDER_ID',
products: [{
productId: 'PRODUCT_ID',
sku: 'PRODUCT_SKU',
purchaseUnitPrice: 10000,
purchaseQuantity: 1,
currency: 'KRW'
}]
});
</script>
前へ ← ミッション 6 · 計測 — 流入と購入次へ → 付録
付録 · 特定の状況でのみ
ミッションには含まれない、特定の状況でのみ必要になる機能です。
A. 有効化が必要な機能
次の 4 つはアカウントで機能が有効になっていないと動きません。コードを入れてもボタン自体が出てこない場合は、まず有効化の有無をご確認ください — ご依頼は ask@shoplive.cloud までお願いします。
ブランドのお気に入り
プレイヤー内のブランドお気に入りボタンです。視聴者がタップすると ON_CLICK_BRAND_FAVORITE_BUTTON が届くので、自社システムに保存したうえでその結果をプレイヤーへ返します。
const messageCallback = {
// プレイヤーが開始したとき、またはブランド情報が変わったとき — 現在のユーザーのお気に入り状態を知らせる
ON_CHANGED_BRAND_FAVORITE: function (payload) {
const player = cloud.shoplive.getPlayer(payload.campaignKey);
if (!player) return;
player.sendMessage('SEND_COMMAND_MESSAGE', {
command: 'SET_BRAND_FAVORITE',
payload: { identifier: payload.identifier, favorite: true }
});
},
// 視聴者がボタンを押したとき — 自社サーバーに保存する
ON_CLICK_BRAND_FAVORITE_BUTTON: function (payload) {
const { identifier, favorite } = payload;
fetch('YOUR_FAVORITE_API', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ identifier, favorite })
});
}
};
cloud.shoplive.initPlugin({ accessKey: 'YOUR_ACCESS_KEY', messageCallback });
プレイヤーを表示するときに初期状態を一緒に渡すこともできます — setPlayer(id, { campaignKey, brand: { identifier, favorite } })。
カートに入れる
商品リストにカートボタンが表示され、タップすると CLICK_PRODUCT_CART が Goods payload と一緒に届きます。自社のカートに入れたあと、入っている状態をプレイヤーへ返すとボタンの見た目が変わります。
CLICK_PRODUCT_CART: function (payload) {
addToMyCart(payload).then(function () {
// 入れている間にプレイヤーが閉じている可能性があるのでここで取得する(ミッション 5)
const player = cloud.shoplive.getPlayer(payload.campaignKey);
if (!player) return;
player.sendMessage('SEND_COMMAND_MESSAGE', {
command: 'SET_PRODUCT_CART_ON',
payload: { products: [{ sku: payload.sku, isCartOn: true }] }
});
});
}
Shopify ストアで platform: 'SHOPIFY' を使う場合は、カートへの追加・取得を SDK が直接処理するので、上のコールバックを実装する必要はありません。
配信リマインド
配信予定(READY)状態の配信カードのタイトル下に「Subscribe」ボタンが表示されます。ボタンは initPlugin() の設定で有効にし、すべての配信予定に出す方法と特定の配信にだけ出す方法の 2 通りがあります。
方法 1 · すべての配信予定に表示
webClientSettings の中に useRemind: true を 1 行追加します。以後に登録される配信予定にも自動で適用されます。
cloud.shoplive.initPlugin({
accessKey: 'YOUR_ACCESS_KEY',
webClientSettings: {
useRemind: true
}
});
方法 2 · 特定の配信にだけ表示
ボタンを出したい配信の campaignId を文字列の配列で渡します。リストにない配信にはボタンは表示されません。入れる値は campaignKey ではなく campaignId です — ガイドの他の箇所で使う配信キーとは別の値で、Admin の配信詳細で確認できます。
cloud.shoplive.initPlugin({
accessKey: 'YOUR_ACCESS_KEY',
listCampaignIdsForRemindButton: ['2262194', '2262195']
});
設定の組み合わせと結果
2 つの設定は併用できます。useRemind が有効なら、リストに関係なくすべての配信予定に表示されます。
useRemind | listCampaignIdsForRemindButton | 結果 |
|---|---|---|
true | 未指定 | 配信予定すべてに表示 |
未指定または false | 指定 | リストにある配信のみ表示 |
true | 指定 | 配信予定すべてに表示 |
未指定または false | 未指定 | 表示しない |
ボタンのクリックを受け取る
視聴者がボタンを押すと ON_CLICK_REMIND_CAMPAIGN が届き、payload.isReminded で申し込みか解除かを判別します。このコールバックに自社のリマインド予約処理をつなげてください。
ON_CLICK_REMIND_CAMPAIGN: function (payload) {
const campaignKey = payload.campaign.campaignKey;
if (payload.isReminded) {
subscribeToMyPush(campaignKey); // リマインドを申し込む
} else {
unsubscribeFromMyPush(campaignKey); // リマインドを解除する
}
}
配信予定の状態でのみ表示されます。配信が始まるか終了すると、ボタンは自動で消えます。コードの設定が Admin の設定より優先されます — Admin でリマインド機能が有効でも、useRemind: false を渡すとボタンは消えます。申し込み状態はブラウザに保存されます — 申し込み後は同じブラウザで「Completed」と表示され、もう一度押すと解除されます。
オークション
リアルタイムのオークション機能です。自社で必ず処理する必要があるのは落札者を決済へ送ることの 1 つだけで、残りのイベントは独自 UI を作ったりログを残したりするときにだけ使います。
落札者を決済へ送る
オークションが終わると落札者に案内シートが表示されます。視聴者がそのシートの決済ボタンを押すと ON_AUCTION_WINNER_CHECKOUT_CLICKED が届きます。
ON_AUCTION_WINNER_CHECKOUT_CLICKED: function (payload) {
// payload.auction.winnerCheckoutScheme に Admin で設定した決済アドレスが入っています
const scheme = payload.auction && payload.auction.winnerCheckoutScheme;
location.href = scheme || ('/checkout?sku=' + payload.product.sku);
}
ON_CLICK_BUY_BUTTON と混同しないでください
ON_CLICK_BUY_BUTTON は商品リストの購入ボタンで、payload は Goods です。落札者の案内シートの決済ボタンはこのイベントを発生させません — オークションの決済を ON_CLICK_BUY_BUTTON だけで処理すると、落札者がボタンを押しても何も起きません。payload の構造
下のオークションのイベントは同じ形の payload を受け取ります — product(商品)と auction(オークション)の 2 つのかたまりです。
| 場所 | 主なフィールド |
|---|---|
payload.product | productId · sku · name · brand · originalPrice · discountPrice · currency · url · imageUrl · stockStatus · auctionStatus |
payload.auction | winnerCheckoutScheme(落札者の決済アドレス)· winner({ name, uid, userId })· leader(現在の最高入札者)· currentPrice · winningPrice · startingPrice · bidRound · bidStatus · endingAt · endedAt · recommendedPrices |
payload.transactionId | 落札者本人にのみ、取引 ID がある場合に ON_AUCTION_WINNER_DETERMINED に併せて載ります |
オークションの進行を追う
| イベント | いつ |
|---|---|
ON_AUCTION_READY | オークションの準備ができたとき |
ON_AUCTION_STARTED | オークションが始まったとき |
ON_BID_STATUS_CHANGED | 入札状況が変わったとき(最高額・入札者の更新) |
ON_BID_RESULT_RECEIVED | 自分が入れた入札の結果が返ってきたとき |
ON_AUCTION_BID_TIME_EXTENDED | 終了間際の入札で終了時間が延長されたとき |
ON_AUCTION_ENDED | オークションが終わったとき |
ON_AUCTION_WINNER_DETERMINED | 落札者が決まったとき(すべての視聴者へ) |
ON_AUCTION_SELF_WON | 自分が落札したとき(落札者本人にのみ) |
入札資格
視聴者が入札しようとして資格がない場合、CAN_BID_REQUIRED が { isLogin: true, canBid: false } と一緒に届きます。ゲストにはこのイベントではなく LOGIN_REQUIRED が届きます — まずログインしてもらう必要があるためです。
canBid で決めます
ユーザー情報を渡すときに canBid で入札可否を指定します(ミッション 2)。ただしプラットフォーム自動連携を使うと canBid: true が必ず付くため、ショップにログインしている人なら誰でも入札できるようになります。会員ランクや購入履歴で資格を絞る必要がある場合は setUserObject() を直接呼んでください。B. PIP — ページを移動しても配信を見続ける
視聴者が配信中に商品をタップすると、商品ページへ移動して配信が途切れます。PIP はページは移動しつつ映像だけを小さく残して視聴を続けさせます。
Shoplive にご依頼いただいて有効化する機能です(ask@shoplive.cloud)。有効化後は自社コードに追加するものはありません — 視聴者が商品をタップすると SDK が自動で PIP に切り替えます。
2 つの方式
| Web PIP | ブラウザ PIP | |
|---|---|---|
| どう見えるか | 自社ページの上に小さなプレイヤーが浮かびます。視聴者がドラッグで動かせ、見た目も Shoplive プレイヤーと地続きです | ブラウザが提供する標準の PIP ウィンドウです。見た目は変えられません |
| どこまで付いてくるか | 同じタブの中でのみ維持されます | 他のタブ・他のサイトへ行っても付いてきます |
| 使える条件 | 遷移先のアドレスが自社と同じドメインである必要があります(Web PIP を使う前に確認する 3 点) | 視聴者が直接押した操作である必要があります(ブラウザ PIP の制約) |
| モバイルでは | 自社ページの上に直接描くのでデスクトップとモバイルで同じです | 弱いです — Android の WebView では限定的で、アプリ内ブラウザでは動作しません。デスクトップ中心とお考えください |
| こんなときに | 自社サイト内で商品詳細へ送るとき · モバイルの比率が高いとき | 外部ドメイン・他サイトへ送るとき · デスクトップの比率が高いとき |
Web PIP を使う前に確認する 3 点
Web PIP は遷移先のページを iframe に収めて画面全体に重ねる方式で動作します。そのため以下のいずれかに引っかかると、有効にしても画面が描画されません。有効化をご依頼になる前にご確認ください。
| 確認すること | 可能 | 不可 |
|---|---|---|
| 同じドメインか | shop.com/live → shop.com/product/1 | shop.com/live → m.shop.com/product/1サブドメインが違うだけでも不可です |
X-Frame-Options ヘッダー | 自社ページに SAMEORIGIN を設定 | DENY だと iframe がまったく描画されません。外部サイトは自社では変更できません |
Content-Security-Policy | frame-src に遷移先のアドレスを許可 | 許可リストになければ描画されません(FAQ · CSP) |
iframe の中で開きます — 既存の機能がそのまま動くか確認してください
同じドメインであっても iframe の中ではブロックされるスクリプトがあります。決済モジュール · 外部ライブラリ · ポップアップなど、これまで使っていた機能が正常に動作するか必ず実際にご確認ください。ここが Web PIP 導入で最もよく引っかかる点です。決済 · ログインのページでは自動的に抜けます
決済のように iframe の中で進めてはいけないページがあります。そのため Web PIP は以下のアドレスへ遷移する瞬間、PIP を解除して本当のページ遷移に切り替えます。
/orderform.html /login.html /basket.html /navercheckout
iframe の中で進んでしまいます。Shoplive 担当者にアドレスをお伝えいただければ追加できます。ブラウザ PIP の制約
- 視聴者が直接押した操作からのみ有効になります。ブラウザのセキュリティ ルールなので、コードから任意に呼び出すことはできません。
- PIP への切り替えと新しいウィンドウを開く操作を同時には行えません。両方必要な場合は、PIP に切り替える操作を先に行い、新しいウィンドウはその次の操作に分けてください。
- モバイル対応が弱いです。デスクトップのブラウザではおおむね動作しますが、Android の WebView(自社アプリ内の Web 画面 · LINE や Instagram のようなアプリ内ブラウザ)では限定的か、まったく動作しません。視聴者の大半がモバイル、あるいはアプリの WebView から来る場合はブラウザ PIP だけでは不十分です — 同じドメイン内で動く導線は Web PIP でカバーし、外部ドメインへ出る導線だけをブラウザ PIP に任せる形で分けてください。
自社コードから直接表示する 任意
既定は自動です — 視聴者がプレイヤー内で商品やリンクをタップすると SDK が自動で PIP に切り替えます(ミッション 3 の CLICK_PRODUCT · LINK のデフォルト動作)。自社 UI の別のボタンから同じ動作を起こしたい場合は次を使います。
// Web PIP に切り替えながら指定したアドレスへ遷移します
cloud.shoplive.navigateWithPIP('/product/1', 'YOUR_CAMPAIGN_KEY');
Web PIP が有効になっていない場合や、該当する配信のプレイヤーがない場合は何も起きません。PIP の状態で視聴者が小さなプレイヤーをタップすると、PIP が解除されて配信画面に戻ります。
C. SPA で使う
initPlugin({ isSPA: true })— クライアント ルーティングでページが変わっても SDK を維持します。initPluginは 1 ページのライフサイクルで1 回だけ動作し、2 回目の呼び出しは無視されます。- コンポーネントが消えるときは
destroyPlayer(id)·destroyOverall(id, true)で片付けてください。コンテナの DOM だけを削除すると、SDK の内部にプレイヤーが残ります。 - 独自ルーターが URL の変化を監視している場合は、モーダルがアドレスを変更しないよう
disableHistoryHookをオンにしてください。initPlugin({ disableHistoryHook: true })でページ全体に適用することもできます。
D. 自社アプリの WebView の中で表示する
配信を組み込んだ Web ページを自社アプリの WebView で開く場合(ハイブリッドアプリ)、WebView 側の設定を変えないと映像が再生されないか、全画面に飛び出します。以下はアプリのコードで一度設定すれば済みます。
| プラットフォーム | 設定 | しないと |
|---|---|---|
iOS(WKWebView) | configuration.allowsInlineMediaPlayback = true | 再生が始まる瞬間にネイティブの全画面プレイヤーへ切り替わり、プレイヤー UI が消えます |
Android(WebView) | settings.mediaPlaybackRequiresUserGesture = false | 視聴者が直接タップするまで自動再生が始まりません |
// iOS — WKWebView を作るとき
let configuration = WKWebViewConfiguration()
configuration.allowsInlineMediaPlayback = true
let webView = WKWebView(frame: rect, configuration: configuration)
// Android — WebView の作成後
webView.settings.mediaPlaybackRequiresUserGesture = false
E. RequireJS / AMD 環境
SDK は映像再生に hls.js を使います。通常は SDK が https://cdnjs.cloudflare.com から <script> タグで直接読み込みますが(CSP を使うならこのオリジンも許可してください)、ページが RequireJS でモジュールを管理していてその方式が使えない場合は、ローダーを渡して代わりに読み込ませます。
cloud.shoplive.initPlugin({
accessKey: 'YOUR_ACCESS_KEY',
useAMD: true,
AMDLoader: require // 省略すると window.require を使います
});
- ページに既に
window.HlsがあればuseAMDは何もしません — SDK がそのオブジェクトをそのまま使います。 AMDLoaderを省略するとwindow.requireで代用します。どちらもなければコンソールにInvalid AMDLoader requirejsを残して中断し、このとき映像が再生されません — 再生されないのに他のエラーが出ていない場合は、まずこのログを確認してください。- 通常の
<script>読み込み環境では使う機会はありません。
F. ショートフォーム SDK と同じページで
ライブ(shoplive.js)とショートフォーム(shoplive-shortform.js)は別のスクリプトですが、同じ window.cloud.shoplive オブジェクトに関数を追加する方式なので、1 ページに一緒に読み込めます。読み込み順は関係ありません。
- 初期化はそれぞれ呼びます —
initPlugin()/initShortform() - ユーザー情報の関数(
setUserObject·setUserJWT·logout)は2 つの SDK で共有されるため、1 回呼べば両方に反映されます。最後に呼んだ値が残ります - ライブのミニプレビューとショートフォームのプレビューは互いを認識しません。どちらも既定の位置が画面の隅なので同じ場所で重なることがあります — 2 つの機能を併用する場合は、どちらかの位置を別の角に指定してください。ライブ側の位置はミッション 4 · 位置とサイズ、ショートフォーム側はショートフォームガイドをご覧ください
ショートフォームの連携方法はショートフォームガイドをご覧ください。
G. ショッププラットフォーム別の設置場所
Cafe24・ゴドモール(Godomall)・WISA・MakeShop・imweb・Shopify で作ったショップで、管理画面のどこにコードを入れるかをまとめました。入れるコードはミッション 1(配信一覧・プレイヤー)とミッション 2 · ステップ 3(ログイン自動連携)と同じで、ここでは場所とプラットフォーム別の会員変数だけを扱います。
- 運用中のスキンをコピーし、編集用スキンで作業します — 保存した瞬間に実際のショップへ反映されるのを防ぎます
- 共通レイアウト(全ページが共有する上部領域)に SDK の読み込み・会員情報の要素・
initPlugin()を入れます — 下のコード ① - 配信一覧を表示するページを新しく作り、
setOverall()を入れます — 下のコード ② - メニュー(入口)にそのページのアドレスをつなぎます
- 配信中にミニプレビューが表示されるか確認します。表示されなければ Admin の配信詳細で API・プラグインの公開をオンにします
① 共通レイアウト
<!-- 共通レイアウト — すべてのページに 1 回だけ(場所は各プラットフォームを参照) -->
<script src="https://static.shoplive.cloud/shoplive.js"></script>
<!-- 会員情報の要素 — プラットフォーム別(下の各プラットフォームを参照) -->
<script>
cloud.shoplive.initPlugin({
accessKey: 'YOUR_ACCESS_KEY', // Admin の配信詳細からコピー
platform: 'CAFE24' // プラットフォームに合った値(imweb は省略)
});
</script>② 配信一覧ページ
<!-- 配信一覧ページ — このページの HTML 領域に -->
<div id="shoplive-overall"></div>
<script defer>cloud.shoplive.setOverall('shoplive-overall');</script>Cafe24
| ログイン | eclogin.cafe24.com/Shop |
|---|---|
| PC | 代表デザイン(대표디자인)をコピー → コピーを選んで修正(수정) → エディタの主要画面(주요화면) › メイン画面(메인화면) → 下部 HTML 領域の <!--@layout(/layout/basic/layout.html)--> から共通レイアウトを開き、<body> のすぐ下に ① |
| 配信一覧ページ | 左下のフォルダ追加(폴더추가)で live フォルダ → 画面追加(화면추가)で live.html(画面分類: 選択なし(自動)) → HTML 領域の既存コードを消して ② |
| 入口 | メニュータブにマウスを乗せて編集(편집) → <a href="/live/live.html"> のようにパスを入力 |
| モバイル | モバイルの代表デザインをコピーして同じ手順 |
| 購入コンバージョン | スキンの order_result.html の </body> 直前 — コードはミッション 6 · プラットフォームで |
会員情報の要素
<div module="Layout_stateLogon" style="display:none;">{$id} {$name}</div>ゴドモール(Godomall)
| ログイン | nhn-commerce.com → 設置するショップを選択 |
|---|---|
| PC | 管理画面 › デザイン(디자인)でスキンをコピーし作業スキンに設定(一覧に WORK と表示) → 全体レイアウト(전체 레이아웃)をダブルクリック › 上部レイアウト(상단 레이아웃) → <body> のすぐ下に ① → デザインページを保存(디자인 페이지 저장) |
| 配信一覧ページ | 入れるフォルダをダブルクリック › 新しいページを追加(새로운 페이지 추가) → ファイル名を入力 → 追加したページに ② → 保存 |
| 入口 | ページの画面表示(화면보기)でアドレスをコピー → 全体レイアウト › 上部デザイン › 上部基本ファイル(상단 기본파일)のタブに貼り付け |
| モバイル | モバイルショップのデザインスキン一覧で同じ手順 |
会員情報の要素
<div style="display:none;">
<span id="cloud-shoplive-user-id">{=gSess.memId}</span>
<span id="cloud-shoplive-user-name">{=gSess.memNm}</span>
</div>WISA
| ログイン | wisa.co.kr → 設置するショップ |
|---|---|
| PC | デザイン › デザイン管理 › スキン管理(디자인 › 디자인관리 › 스킨 관리) — 使用中のスキンではなく編集スキンに反映され、編集スキンのプレビューで確認します → HTML 編集 › 上部共通ページ編集(상단공통페이지 편집)の一番上に ① |
| 配信一覧ページ | HTML 編集 › 追加ページ編集(추가 페이지 편집) → ページ名を入力 → 内容編集(내용편집) → エディタを HTML に切り替え → ② → 確認 |
| 入口 | ページのファイル名を押してアドレスをコピー → 上部共通ページ編集のタブに貼り付け |
| モバイル | モバイル › スキン管理で同じ手順。追加ページは属性修正(속성수정)でモバイルページ使用 = 使用する(모바일페이지 사용 = 사용함)にしてからモバイル追加ページに切り替えて入力 |
会員情報の要素
<div style="display:none;">
<span id="cloud-shoplive-user-id">{{$회원아이디}}</span>
<span id="cloud-shoplive-user-name">{{$회원명}}</span>
</div>MakeShop
platform: 'MAKESHOP' はミッション 2 · ステップ 3の対応値一覧にありません。ショートフォーム SDK のソースではこの値の処理が無効(コメントアウト)になっており、ライブ SDK での対応可否は確認中です。下は以前のドキュメント(Document360)の方法です。ログイン名がチャットに表示されなければ、ミッション 2 · ステップ 2のように setUserObject() を直接呼んでください。| ログイン | makeshop.co.kr |
|---|---|
| PC | 個別デザイン(개별 디자인)で設置するスキンのデザイン編集(디자인 편집하기) → 基本上部(기본 상단)に ①(会員情報・platform は下のコード) |
| 配信一覧ページ | 配信一覧を表示するページに ② |
| 入口 | ② を入れたページのアドレスをメニューのパスに指定 |
| モバイル | モバイル D4(個別デザイン) › HTML デザイン編集(HTML 디자인 편집하기) › 基本上部で同じ手順 |
会員情報の要素
<div style="display:none;">
<span id="cloud-shoplive-user-id"><!--/user_id/--></span>
<span id="cloud-shoplive-user-name"><!--/user_name/--></span>
</div>
<script>cloud.shoplive.initPlugin({ accessKey: 'YOUR_ACCESS_KEY', platform: 'MAKESHOP' });</script>imweb
platform の値がありません。imweb がログイン会員に入れておく window.MEMBER_UID で setUserObject() を呼ぶ方法(ミッション 2 · ステップ 2)です。この変数は imweb 側の動作なので、ショップごとに値があるか確認してください。| 場所 | imweb 管理画面 › デザイン編集 › 共通レイアウトの <head> に下のコード — すべてのページに入っていないとミニプレビューが動きません |
|---|---|
| 配信一覧ページ | 配信一覧を表示するページの HTML ウィジェット(または body 領域)に ② |
| 注意 | initPlugin() が 1 ページに 2 回入らないようにします。サーバーが必要な JWT セキュア認証(ミッション 2)は imweb では使えません |
<script src="https://static.shoplive.cloud/shoplive.js"></script>
<script>
cloud.shoplive.initPlugin({ accessKey: 'YOUR_ACCESS_KEY' });
if (window.MEMBER_UID) { // imweb がログイン会員に入れておく会員番号
cloud.shoplive.setUserObject({ userId: window.MEMBER_UID });
}
</script>Shopify
Shopify アプリ(ShopliveAssistant)で接続 — 推奨
- Shopify App Store の ShopliveAssistant ページで、右上のアカウントアイコンから連携するストアで合っているか確認します
- Install → アプリが求める権限(担当者情報・商品データなど)を確認してインストールを終えます
- Shopify 管理画面の Apps › Shoplive Assistant で Shoplive アカウントにログインします
- ストアにつながった Access Key を確認し(編集可)、商品同期で Shopify の商品を Shoplive に取り込みます — 最近の変更分のみ / オプションを個別商品として、から選択
- アプリはアカウント連携と商品同期までです。プレイヤーは下のテーマコードで設置します
| PC・モバイル共通 | オンラインストア › テーマ › 現在のテーマのアクション › コードを編集 → theme.liquid の <body> のすぐ下に下のコード |
|---|---|
| 配信一覧ページ | オンラインストア › ページ › ページを追加 → 内容を HTML に切り替えて下の ② のコード |
| 入口 | オンラインストア › ナビゲーションでメニューにそのページを追加 |
| 購入コンバージョン | 設定 › カスタマーイベント › カスタムピクセル — コードはミッション 6 · プラットフォームで |
| カート | platform: 'SHOPIFY' ならプレイヤー内のカート追加・照会を SDK が処理します — A. 有効化が必要な機能 |
theme.liquid — ログイン中の顧客は Liquid 変数で渡します
<script src="https://static.shoplive.cloud/shoplive.js"></script>
<script>
cloud.shoplive.initPlugin({ accessKey: 'YOUR_ACCESS_KEY', platform: 'SHOPIFY' });
{% if customer %}
cloud.shoplive.setUserObject({ userId: "{{ customer.id }}", userName: "{{ customer.first_name }}" });
{% endif %}
</script><div id="shoplive-overall"></div>
<script defer>
document.addEventListener('DOMContentLoaded', function () {
cloud.shoplive.setOverall('shoplive-overall');
});
</script>関数インデックス
cloud.shoplive.* のうち Web 連携で使う関数の一覧です。名前が分かっているとき、どの節を見ればよいか探すためのものです。
| グループ | 関数 | ガイド |
|---|---|---|
| 初期化 | initPlugin(config) | クイックスタート · フィールド |
| プレイヤー | setPlayer(containerId, config) · destroyPlayer(containerId) | ミッション 1 · 方法 A · フィールド |
| ライブページ テンプレート | setOverall(containerId, config?) · destroyOverall(containerId?, removeActivePlayer?) | ミッション 1 · 方法 C · フィールド |
| モーダル | showFeaturedPlayerModal(config) · dismissLayerModalPlayer() | ミッション 1 · モーダルで表示する |
| ミニプレビュー | showLiveMiniPreview() · dismissLiveMiniPreview() · setOnClickLiveMiniPreview(fn) | ミッション 4 · ミニプレビュー |
| 配信カード · カバー | setLivePreview(containerId, config) · destroyLivePreview(containerId?) · setOnAirCover(containerId) · setLandscapeOnAirCover(containerId) · setFeaturedCampaign(containerId, config) | ミッション 4 · 配信カード |
| ユーザー | setUserObject(user) · setUserJWT(jwt) · logout() | ミッション 2 |
| イベント | (initPlugin のオプション)messageCallback | ミッション 3 · イベント辞典 |
| プレイヤー制御 | getPlayer(key?) · getActivePlayers() · player.sendMessage(action, payload) | ミッション 5 · コマンド辞典 |
| PIP | navigateWithPIP(url, campaignKey?) | 付録 B · PIP |
| 購入コンバージョン | sendConversionEvent(event) | ミッション 6 |
この表にない名前が cloud.shoplive に見える場合は、モバイルアプリ SDK 連携用か Shoplive 内部用です。Web 連携では使いません。
前へ ← 付録次へ → 設定オブジェクト フィールド辞典
設定オブジェクト フィールド辞典
各関数に渡す設定オブジェクトにどんな値を入れられるかをまとめた一覧です。accessKey と campaignKey を除けばほとんどが任意項目なので、必要なものだけ入れて残りは空にしておけば、デフォルト値またはアカウント設定で動作します。
containerId は配信キーではなく自社ページの DOM 要素の id です
setPlayer · setOverall · setLivePreview · setOnAirCover はあらかじめページに用意した空の要素の中に画面を描きます。そのため第 1 引数は、描く場所である <div> の id 属性の値です。CSS セレクタではなく document.getElementById() で探すので # は付けません。その id を持つ要素が見つからない場合はコンソールに Invalid containerId を残し、何も描画しません。初期化 — initPlugin(config)
| フィールド | 必須 | 説明 |
|---|---|---|
accessKey | 必須 | Shoplive が発行する顧客識別キー |
messageCallback | 任意 | イベントごとの動作を定義する関数マップ(ミッション 3) |
userObject / userJWT | 任意 | ログインユーザーの情報。あとから setUserObject / setUserJWT で変更可能(ミッション 2) |
platform | 任意 | ショップのログイン状態を SDK に読み取らせます — 'CAFE24' · 'WISA' · 'GODOMALL' · 'SHOPIFY'(ミッション 2 · ステップ 3) |
shareUrl | 任意 | 共有ボタンが送るアドレス。指定しなければ現在のページのアドレス(ミッション 4 · 共有 URL) |
useAutoPreview | 任意 | false なら初期化時にミニプレビューを自動表示しません(ミッション 4) |
isSPA | 任意 | true ならページ遷移時も SDK を維持(付録 C) |
disableHistoryHook | 任意 | true ならモーダルが開くときにアドレスを変更しません(付録 C) |
listCampaignIdsForRemindButton | 任意 | リマインドボタンを出す配信の campaignId 一覧(付録 A) |
webClientSettings.useRemind | 任意 | true にすると、配信予定のすべての配信にリマインドボタンを表示します。Admin の設定より優先されます(付録 A) |
anonId | 任意 | 自社が管理する未ログイン識別子。コンバージョン集計に併せて使われます。?anonId= のクエリで渡しても認識されます(ミッション 6) |
gaId | 任意 | Google Analytics のクライアント ID。Shoplive の記録と GA のデータを同じユーザーとして揃えるとき |
customerDeviceId | 任意 | 自社で使う端末識別 ID。SDK が送るリクエストに併せて載ります |
useAMD / AMDLoader | 任意 | RequireJS 環境(付録 E) |
ここにない値をコードで見かけた場合。モバイルアプリの WebView で SDK を表示するときにアプリが渡す値(広告識別子など)か、特定の顧客と個別に取り決めた値、あるいは Shoplive の開発用の値です。Web ページに直接連携する場合には使いません。
プレイヤー — setPlayer(containerId, config)
| フィールド | デフォルト | 説明 |
|---|---|---|
campaignKey | 必須 | 再生する配信のキー。ないとコンソールに Invalid AccessKey or CampaignKey |
ui.viewerCount | true | 視聴者数を表示 |
ui.likeCount | true | いいね数を表示 |
ui.backButton | false | 戻るボタンを表示 |
ui.shareButton | false | 共有ボタンを表示 |
isFullScreen | false | 常に全画面で実行(viewport meta が必要) |
hideControls | false | コントロール UI を隠した状態で開始 |
playerAlias | — | getPlayer('別名') で取り出すための別名(ミッション 5) |
closePlayerAfterCampaignEnd | — | 配信終了からこの時間(ms)が経つと CLOSE_PLAYER イベントが届きます。SDK はこのイベントで何もしないので、プレイヤーを実際に片付けるには destroyPlayer() または dismissLayerModalPlayer() を自分で呼ぶ必要があります。指定しない場合は、配信終了の 30 秒後にプレイヤーが自分で再読み込みします(終了画面に落ち着きます) |
chatFilterPatterns | — | 正規表現文字列の配列。一致したチャットは送信されず ON_FILTERED_CHAT が発生 |
passcode | — | リハーサル配信の入場コード |
brand | — | ブランドのお気に入りの初期状態 — { identifier, favorite }(付録 A) |
ライブページ テンプレート — setOverall(containerId, config)
| フィールド | デフォルト | 説明 |
|---|---|---|
featuredOnly | false | メイン配信(プレイヤー)領域のみ表示 |
featured.fixedCampaignKey | — | メイン配信を特定の配信に固定 |
campaignListsOnly | false | 配信リスト領域のみ表示 |
campaignStatus | すべて | 'READY' · 'ONAIR' · 'CLOSED'。文字列または配列(書いた順に並びます) |
tags / tagSearchOperator | — | タグ フィルター · 'OR' | 'AND' |
displayTags | — | リストの上にフィルタータブとして出すタグ |
skus / goodsIds | — | 特定の商品を含む配信のみ — 自社の商品コード / Shoplive 内部の商品 ID |
campaignList.layout | 'GRID' | 'GRID' · 'HORIZONTAL' |
campaignList.type | — | 'SECTION' — ステータス別のセクションに分けて表示 |
hasMoreButton | true | false なら 'GRID' で無限スクロール |
ascending | ステータス次第 | 並び順。未指定なら campaignStatus が 'READY' の文字列 1 つのときだけ昇順 |
sectionTitles | 既定の文言 | { onair, ready, closed, all } |
disableHistoryHook | false | リストからモーダルを開くときにアドレスを変更しない |
その他の関数
| 関数 | 設定オブジェクト |
|---|---|
showFeaturedPlayerModal(config) | campaignKey(必須)· disableHistoryHook |
setLivePreview(containerId, config) | campaignKey(必須)· onClick(campaign) |
setFeaturedCampaign(containerId, config) | campaignKey(必須)· playerContainerId · playerAlias |
sendConversionEvent(event) | accessKey · eventType(どちらも必須)· orderId · products[] · timestamp · custom · userObject / userJWT(ミッション 6) |
ユーザー情報 — setUserObject(user)
userId 以外はすべて任意です。JWT 認証のクレーム名はミッション 2 · ステップ 5 をご覧ください(チャットの表示名が userName ではなく name です)。
| フィールド | 説明 |
|---|---|
userId | 必須。ログインユーザーの一意な ID。空ならゲスト扱いです |
userName | チャットに表示される名前。禁止ワードは * に置き換えて表示されます |
gender · age | 統計用。'm' / 'f'、年齢は 5 歳単位にグループ化して集計されます |
userScore | -100 〜 100 の整数。入場制限や抽選対象の制限の基準に使えます |
userType | 入場制限(Entry Type)が設定された配信で参照される値(例: 'VIP') |
profile | チャット一覧に表示するプロフィール画像の URL。推奨 64×64px |
custom | 自由形式のデータ、最大 1KB |
canBid | true / false。オークションの入札資格(付録 A · オークション)。プラットフォーム自動連携はこの値を常に true にします |
イベント辞典
initPlugin({ messageCallback }) に登録できるイベントの一覧です。使い方と例はミッション 3 にあり、ここは名前から素早く探すためのものです。画面列の番号は画面の用語ガイドの図に対応します。
デフォルト動作があるイベント — 登録すると置き換わります
登録しなくても SDK が自動で処理します。登録した瞬間デフォルト動作は実行されなくなるので、ログだけ取るつもりでも元の動作を自分で作り直す必要があります。
| イベント | デフォルト動作 | 画面 |
|---|---|---|
CLICK_PRODUCT | 新しいウィンドウで payload.url へ遷移 | ⑥ |
LINK | 同じウィンドウで payload.url へ遷移(Web PIP がオンならプレイヤーを維持) | ⑨ ⑩ ⑪ |
LINK_NEW_WINDOW | 新しいウィンドウで payload.url へ遷移 | ⑨ ⑩ ⑪ |
CLICK_SHARE_BTN | OS の共有シート(navigator.share)→ なければクリップボードへコピー(共有 URL) | ⑫ |
CLICK_BACK_BUTTON | history.back() | ⑫ |
ON_CLICK_CAMPAIGN_LIST_ITEM | モーダル プレイヤーを開く | — |
ON_CLICK_CLOSE_PLAYER_MODAL | モーダル プレイヤーを閉じる | — |
ON_CLICK_SCHEME_BUTTON | 新しいウィンドウで payload.scheme を開く。payload.schemeType は GO_PRODUCT · ADD_PRODUCT · REMOVE_PRODUCT · WINNER_CHECKOUT | ⑥ |
REQUEST_FULL_SCREEN · EXIT_FULL_SCREEN | ブラウザの全画面へ切り替え · 解除 | ① |
デフォルト動作がないイベント — 登録して初めて何かが起きます
| イベント | いつ | 画面 |
|---|---|---|
DOWNLOAD_COUPON | クリック動作が「クーポンダウンロード」のポップアップをタップしたとき。登録しないと何も起きません | ⑨ ⑩ ⑪ |
CUSTOM_ACTION | クリック動作が「カスタム」のポップアップをタップしたとき | ⑨ ⑩ ⑪ |
LOGIN_REQUIRED | ゲストがログインの必要な機能にアクセスしたとき | ⑦ |
この 3 つは、Shoplive Admin のポップアップ設定で選んだクリック動作がそのままイベント名になって届きます。設定した動作と登録したイベント名がずれるとコールバックが呼ばれないので、ミッション 3 の Admin 設定の表も併せてご覧ください。
通知だけを受け取るイベント
ON_PLUGIN_INITIALIZED · ON_PLAYER_STARTED · NOW_ONAIR_CHECKED · ON_CAMPAIGN_STATUS_CHANGED · ON_CHANGED_VIEWER_STAT · ON_PLAYER_MODAL_SHOWN · ON_PLAYER_MODAL_HIDDEN · ON_LIVE_MINI_PREVIEW_SHOWN · ON_LIVE_MINI_PREVIEW_HIDDEN · ON_CLICK_CLOSE_LIVE_MINI_PREVIEW · ON_PRODUCT_LIST_SHOWN · ON_CHANGED_CAMPAIGN_PRODUCT_LIST · ON_FILTERED_CHAT · ON_RECEIVED_CHAT · ON_ERASED_CHAT · ON_CHAT_INPUT_FOCUS_IN · ON_CHAT_INPUT_FOCUS_OUT · ON_UID_ISSUED — 発生タイミングと payload はミッション 3 · 通知だけを受け取るイベントにあります。
コマンドへの応答としてのみ届くイベント — CURRENT_PLAYBACK_TIME は GET_CURRENT_PLAYBACK_TIME を送ったときにだけ届きます。自分から発生することはありません。
有効化が必要な機能のイベント
| 機能 | イベント |
|---|---|
| ブランドのお気に入り | ON_CHANGED_BRAND_FAVORITE · ON_CLICK_BRAND_FAVORITE_BUTTON |
| カート | CLICK_PRODUCT_CART ·(Shopify)CLICK_SHOPIFY_CART · ADD_TO_SHOPIFY_CART · REMOVE_TO_SHOPIFY_CART · REDIRECT_TO_SHOPIFY_CART_PAGE |
| 配信リマインド | ON_CLICK_REMIND_CAMPAIGN |
| オークション | ON_AUCTION_WINNER_CHECKOUT_CLICKED · ON_AUCTION_READY · ON_AUCTION_STARTED · ON_AUCTION_ENDED · ON_BID_STATUS_CHANGED · ON_BID_RESULT_RECEIVED · ON_AUCTION_BID_TIME_EXTENDED · ON_AUCTION_WINNER_DETERMINED · ON_AUCTION_SELF_WON · CAN_BID_REQUIREDON_CLICK_BUY_BUTTON はオークション専用ではなく商品リストの購入ボタンです |
行動ログ — EVENT_LOG
プレイヤー内のボタンのタップや表示を 1 つのイベントにまとめて受け取ります。51 個すべての名前はミッション 3 · ユーザー行動のログにあります。
この文書にないイベント名が届いた場合は、モバイル SDK の WebView や Shoplive の運用ツールが使う内部イベント、または特定の顧客と個別に取り決めた機能のイベントです。通常の Web 連携では処理する必要はありません。
前へ ← 設定オブジェクト フィールド辞典次へ → プレイヤー コマンド辞典
プレイヤー コマンド辞典
getPlayer().sendMessage(コマンド, payload) で送れるコマンドです。使い方はミッション 5 にあります。画面列の番号は画面の用語ガイドの図に対応します。
| コマンド | payload | 動作 | 画面 |
|---|---|---|---|
removeCoupon | なし | クーポン ポップアップを削除 | ⑨ |
removeBanner | なし | バナー ポップアップを削除 | ⑪ |
removeNotice | なし | お知らせ ポップアップを削除 | ⑩ |
mute · unmute | なし | ミュートのオン · オフ | ⑧ |
playVideo · pauseVideo | なし | 再生 · 一時停止 | ① |
videoRefresh | なし | 映像を読み込み直す | ① |
hideControls · showControls | なし | コントロール UI の非表示 · 表示 | ⑦ |
dismissGoodsList | なし | 商品リストのポップアップを閉じる | ⑥ |
showDialog | { title, message } + cancelText · confirmText · confirmTextColor · confirmBackgroundColor | ダイアログを表示(ミッション 5) | — |
showToast | { message } + duration · position | トーストを表示(ミッション 5) | — |
GET_CURRENT_PLAYBACK_TIME | なし | 現在の再生位置を問い合わせる → CURRENT_PLAYBACK_TIME イベントで応答(ミッション 5) | — |
SEND_COMMAND_MESSAGE | { command, payload } | 下のサブコマンドを運ぶ封筒 | — |
SEND_COMMAND_MESSAGE のサブコマンド
有効化が必要な機能で状態を返すときに使います。
| command | payload | 使う場面 |
|---|---|---|
SET_BRAND_FAVORITE | { identifier, favorite } | ブランドのお気に入り — 現在のユーザーのお気に入り状態を知らせます |
SET_PRODUCT_CART_ON | { products: [{ sku, isCartOn }] } | カート — 入っている状態を知らせてボタンの見た目を変えます |
const player = cloud.shoplive.getPlayer();
player.sendMessage('SEND_COMMAND_MESSAGE', {
command: 'SET_PRODUCT_CART_ON',
payload: { products: [{ sku: 'PRODUCT_SKU', isCartOn: true }] }
});
この表にないコマンド名をコードで見かけた場合は、モバイル SDK の WebView や Shoplive の運用ツールが使う内部コマンドです。Web 連携では使いません。
前へ ← イベント辞典次へ → トラブルシューティングと FAQ
トラブルシューティングと FAQ
プレイヤーが表示されません
まずブラウザのコンソールを確認してください。次の警告が出ていれば原因がすぐ分かります。
| コンソールのメッセージ | 原因 |
|---|---|
Invalid containerId | コンテナ div の id が setPlayer に渡した値と一致していない |
Invalid AccessKey or CampaignKey | setPlayer に渡した campaignKey が空、または欠けている |
Invalid AccessKey | setOverall · setLivePreview などで accessKey が見つからない。initPlugin から受けた値も、関数に直接渡した値もない場合です |
Empty AccessKey | initPlugin の accessKey が空 |
Invalid WebClientSettings | accessKey が誤っているか、初期設定の取得に失敗 — 下の注意を参照 |
Invalid WebClientSettings が見えたら、そのあとの呼び出しはすべて消えます
初期化は設定をサーバーから受け取ったあとに完了します。その前に呼んだ setPlayer · setOverall · sendConversionEvent はいったんキューに溜まり、初期化が終わる瞬間にまとめて実行されますが、設定の取得に失敗すると初期化が終わらないため、キューは永遠に実行されません。自動リトライもありません。
そのため症状は「エラーも出ず、何も起きない」ように見えます。ほかに警告がないのにプレイヤーもコンバージョン イベントも動かない場合は、まずこの行がコンソールにあるか確認してください。
accessKey のタイプミスと、ネットワーク・ファイアウォールによる遮断が主な原因です。コンソールに警告がない場合は、その配信が Admin で公開設定になっているか確認してください — 新規の配信は既定で非公開のため、プラグイン・API の公開設定をオンにしないと campaignKey が正しくてもプレイヤーは表示されません。
なお initPlugin() より setPlayer() を先に呼んでも(順序が入れ替わっても)内部で待機して自動的に処理されるので、スクリプトの順序自体が原因になることはまれです。
商品をタップしても何も起きません
CLICK_PRODUCT を上書きしなければ、既定では新しいウィンドウで商品 URL が開きます。同じウィンドウで遷移させたい場合はコールバックを上書きしてください(ミッション 3)。
プレイヤーの内部(チャット・商品リストなど)の位置を変えられますか?
単なる位置調整にとどまらず、貴社の BI・CI とスタイルガイドを反映した専用デザインのカスタム開発も可能です。ご希望の際は Shoplive 担当者までお問い合わせください。
ただし自社側のコードで直接調整することはできません。下のようにプレイヤーは iframe の中で別ページとして動作するため、ページに適用した CSS は内部には届かないからです。
自社の Web ページ
└─ Player SDK(スクリプト)
└─ <iframe>
└─ Shoplive Player(別ページとして動作)
プレイヤーを収めるコンテナ(div)の位置・サイズはページの CSS で調整できますが、iframe の内部(チャット・商品リストなど)はその境界の中で Shoplive Player 自身のレイアウトに従います。
ミニプレビュー バナーが出したくないページにも表示されます
配信中は initPlugin() を呼んだすべてのページに自動で出るのが既定の動作です。出すページを選びたい場合は、初期化で自動表示をオフにして、出したいページでだけ自分で呼び出してください。
cloud.shoplive.initPlugin({
accessKey: 'YOUR_ACCESS_KEY',
useAutoPreview: false // 自動表示をオフ
});
// 出したいページでだけ
cloud.shoplive.showLiveMiniPreview();
詳しい条件と表示位置はミッション 4 · ミニプレビューにあります。
同じ場所に別の配信で setPlayer をもう一度呼んでも大丈夫ですか?
はい。同じコンテナ id で setPlayer をもう一度呼ぶと、既存のプレイヤーを片付けて新しいプレイヤーに差し替えます。React などでページ遷移なしにコンポーネントが再レンダリングされる場面でも安全に呼び直せます。
ただしコンポーネントが画面から完全に消える(コンテナごと削除される)場合は事情が異なります。SDK がこのタイミングを自動で検知できず、内部的にプレイヤーが有効なまま残り、そのためミニプレビューが正しく表示されないことがあります。コンテナを削除する前に cloud.shoplive.destroyPlayer("コンテナ id") を先に呼んでください。
配信が終わったらアーカイブ(リプレイ)はどう開きますか? campaignKey を変える必要はありますか?
いいえ、campaignKey はそのまま使います。同じキャンペーンが ONAIR → CLOSED にステータスだけ変わるもので、Admin でその配信の「リプレイ公開」設定がオンになっていれば、終了後も同じ campaignKey でアーカイブが正常に再生されます。
映像が自動再生されず、静止画のままです
ブラウザが音声付き映像の自動再生をブロックするためです。SDK はミュート状態で再生を試みますが、端末や設定によってはそれも阻まれ、視聴者が一度タップする必要があります。コードで回避できる領域ではありません。
iOS で特定の端末だけ静止画になる場合は、その端末の設定 → アクセシビリティ → 動作 →「ビデオプレビューの自動再生」がオフになっていないか確認してください。低電力モードやデータ節約モードも同じ結果になります。
自社アプリの WebView で開いたページの場合は原因が異なります — WebView の設定によるものなので、アプリのコードで直せます。付録 D をご覧ください。
CSP(Content-Security-Policy)を使っています。どのドメインを許可すればよいですか?
プレイヤーは iframe の中で別ページとして動作します。そのため自社ページの CSP が関わるのは SDK スクリプトと iframe を表示するところまでで、映像やチャットのように iframe の内部で行われる通信は自社 CSP の適用対象ではありません。
| ディレクティブ | 許可するオリジン | 用途 |
|---|---|---|
script-src | https://static.shoplive.cloudhttps://cdnjs.cloudflare.com | SDK 本体 · hls.js — SDK が映像再生用の hls.js を自社ページに直接読み込むため、Shoplive のドメインではないこのオリジンも必要です。漏らすと SDK は表示されるのに映像だけ再生されません |
style-src | https://static.shoplive.cloud · 'unsafe-inline' | SDK のスタイルシート · アカウントのカスタム スタイル(インライン) |
frame-src | https://static.shoplive.cloud | プレイヤーの iframe — 漏らすとプレイヤーの場所が空のまま残ります |
connect-src | https://config.shoplive.cloud · https://capi.shoplive.cloud · https://api.shoplive.cloud · https://*.shoplive.cloud | アカウント設定 · 配信リスト API · コンバージョン イベント · イベントログ |
img-src | https://image.shoplive.cloud · https://*.shoplive.cloud | ポスター · サムネイル · プロフィール画像 |
正確な API ホストはアカウント設定により異なる場合があるので、リリース前にネットワークタブでご確認ください。
外部スクリプトを CDN から取得することがポリシー上禁止されている場合は、ページで先に hls.js を読み込んで window.Hls を用意しておけば、SDK はそのオブジェクトをそのまま使います(付録 E)。
プレイヤーの UI 言語を変えられますか?
プレイヤー内の文言は視聴者のブラウザの言語設定(navigator.language)に従います。19 言語に対応しており、コードから強制的に指定する公開オプションはありません。
特定の言語に固定する必要がある場合は Shoplive 担当者までお問い合わせください — アカウント・テーマの設定で対応できる場合があります。
initPlugin を 2 回呼んだら、2 回目の設定が反映されません
初期化はページごとに 1 回だけ処理されます。2 回目の initPlugin() の呼び出しは警告もなく静かに無視され、そこに渡した accessKey · messageCallback · useAutoPreview も一緒に捨てられます。
React の StrictMode のようにコンポーネントが 2 回マウントされる環境や、SPA でルーティングのたびに初期化を呼ぶ構造でよく踏みます。初期化はアプリのエントリーポイントで 1 回だけ呼び、ページごとに変わるものは setPlayer 側で処理してください(付録 C)。
コールバックをあとから変えたい場合は、初期化を呼び直すのではなく setPlayer の messageCallback を使ってください — こちらは配信ごとに個別に渡せて、初期化時に渡したものより優先されます。
PIP が動作しません
PIP には 2 種類あり、原因も異なります。付録 B に条件をまとめているので、まずどちらなのかを確認してください。
- Web PIP — 遷移先のページが3 つの条件(同一オリジン ·
X-Frame-Options·frame-ancestors)のいずれかに反すると、画面が空になるか PIP が消えます。決済 · ログインのページでは意図的に抜けるようになっています。 - ブラウザ PIP — 視聴者が直接押す操作がないと始まらず、Android の WebView では限定的です。
どちらもアカウントで利用できるよう設定されている必要があるので、条件をすべて満たしても動かない場合は Shoplive 担当者までお問い合わせください。
購入コンバージョンが計測されません
sendConversionEvent() も初期化が終わる前に呼ぶとキューに溜まり、初期化完了の時点で実行されます。そのため初期化が失敗するとコンバージョン イベントも一緒に消えます — コンソールに Invalid WebClientSettings がないかまず確認してください(上のプレイヤーが表示されませんを参照)。
決済完了ページのようにプレイヤーがないページでも、initPlugin() を先に呼ばないとコンバージョンは送信されません。送る場所とフィールドはミッション 6、視聴記録と結び付く基準はステップ 3 にあります。
TypeScript プロジェクトですが、型定義はありますか?
公式に提供している型定義(.d.ts)はありません。window.cloud.shoplive を any として宣言するか、この文書に記載のフィールドをもとに必要な分だけ自分で型を宣言してお使いください。