NPS Popup / Lightweight template
Cxense is proud to welcome publishers and media companies in Japan, to a seminar at the Royal Norwegian Embassy in Tokyo on May 28th.
As the first Cxense Japan event in 2013 was a great success and attended by over 80 publishers and media contacts, we have decided to host another event this year.
The seminar will provide Cxense customers and contacts in the Japanese publishing world with valuable industry updates, and serve as a networking forum for media companies.
The seminar will feature two Cxense case studies with esteemed guest speakers from DMM.com Lab and MediaGene, as well as an industry update from Cxense's founder Dr. John M. Lervik, and an update and demo of the newly launched Cxense DMP solution by its Product Manager, Mr. Jan Helge Sageflaat coming in from Oslo, Norway, for the event.
As the first Cxense Japan event in 2013 was a great success and attended by over 80 publishers and media contacts, we have decided to host another event this year.
The seminar will provide Cxense customers and contacts in the Japanese publishing world with valuable industry updates, and serve as a networking forum for media companies.
Procedure - Template
- Piano Activation にログインする
- 「管理」メニュー → 「テンプレート」でテンプレート画面に遷移
- 左上のセレクタで、「Lightweight templates」を選択する
- 右上の「テンプレート追加」をクリック
- 任意のテンプレートタイトルを入力し、USE CASE を「Lightweight adblock」に設定し「ライブラリに追加」をクリックする
- 作成したテンプレートを開き、「</> (コードを編集)」をクリックする
- 以下の Template HTML、Template CSS、Template JAVASCRIPT のコードをコピーしてペーストする
- 同様にコンテンツフィールドの入力項目設定を以下の Template Content Fields の例を参考に作成し、カラーコードなどの値はカスタマイズする
- 「保存」をクリックする
Template HTML/JSX
<div class="pn-nps">
<div class="pn-nps__close" onClick={() => context.close()}> <svg viewBox="0 0 24 24" style="fill:[%% close_color %%];"> <path d="M19 6.41l-1.41-1.41-5.59 5.59-5.59-5.59-1.41 1.41 5.59 5.59-5.59 5.59 1.41 1.41 5.59-5.59 5.59 5.59 1.41-1.41-5.59-5.59z"/> <path d="M0 0h24v24h-24z" fill="none"/> </svg> </div>
{/* スコア選択画面 */} <Show when={currentScreen() === 'score'}> <div class="pn-nps__screen"> <div class="pn-nps__title">[%% title %%]</div> <div class="pn-nps__question">[%% question %%]</div> <div class="pn-nps__scores"> <For each={scores}> {(score) => ( <button class="pn-nps__score-btn" classList={{ 'pn-nps__score-btn--selected': selectedScore() === score }} style={selectedScore() === score ? { 'background-color': '[%% accent_color %%]', 'color': '#fff', 'border-color': '[%% accent_color %%]' } : {}} onClick={() => selectScore(score)} > {score} </button> )} </For> </div> <div class="pn-nps__scale-labels"> <span>[%% low_label %%]</span> <span>[%% high_label %%]</span> </div> </div> </Show>
{/* コメント入力画面 */} <Show when={currentScreen() === 'comment'}> <div class="pn-nps__screen"> <div class="pn-nps__score-display"> <span class="pn-nps__score-value" style="color:[%% accent_color %%];">{selectedScore()}</span> <span class="pn-nps__score-max"> / 10</span> </div> <div class="pn-nps__question">[%% comment_question %%]</div> <textarea class="pn-nps__textarea" placeholder="[%% comment_placeholder %%]" onInput={(e) => { setComment(e.target.value); setCommentError(''); }} rows={4} /> <div class="pn-nps__error" classList={{ 'pn-nps__error--hidden': !commentError() }}>コメントを入力してください</div> <PianoPrimaryButton width="100%" onClick={onSubmit} > [%% submit_label %%] </PianoPrimaryButton> </div> </Show>
{/* サンクス画面 */} <Show when={currentScreen() === 'thanks'}> <div class="pn-nps__screen pn-nps__screen--thanks"> <svg class="pn-nps__check-icon" viewBox="0 0 24 24" style="fill:[%% accent_color %%];"> <path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/> </svg> <div class="pn-nps__thanks">[%% thanks_message %%]</div> </div> </Show>
</div>Template CSS
.pn-nps { position: relative; background: #ffffff; border-radius: 12px; padding: 28px 24px 24px; font-family: sans-serif; box-sizing: border-box;}
.pn-nps__close { position: absolute; top: 10px; right: 10px; cursor: pointer; padding: 4px; line-height: 0; transition: transform 0.2s ease; z-index: 1;}
.pn-nps__close:hover { transform: scale(1.3);}
.pn-nps__close svg { width: 1.5em; height: 1.5em; vertical-align: top; pointer-events: none;}
.pn-nps__screen { display: flex; flex-direction: column; gap: 16px;}
.pn-nps__title { font-size: 1em; font-weight: 700; color: #111111; padding-right: 24px;}
.pn-nps__question { font-size: 0.9em; color: #444444; line-height: 1.6;}
.pn-nps__scores { display: flex; flex-wrap: nowrap; gap: 6px; overflow-x: auto;}
.pn-nps__score-btn { flex-shrink: 0; width: 38px; height: 38px; border: 1.5px solid #cccccc; border-radius: 6px; background: #ffffff; cursor: pointer; font-size: 0.85em; font-weight: 600; color: #333333; transition: all 0.15s ease; padding: 0;}
.pn-nps__score-btn:hover { border-color: #999999; background: #f5f5f5;}
.pn-nps__scale-labels { display: flex; justify-content: space-between; font-size: 0.72em; color: #888888;}
.pn-nps__textarea { width: 100%; border: 1.5px solid #cccccc; border-radius: 6px; padding: 10px 12px; font-size: 0.9em; line-height: 1.5; resize: vertical; box-sizing: border-box; font-family: inherit; outline: none; color: #333333;}
.pn-nps__textarea:focus { border-color: #888888;}
.pn-nps__score-display { text-align: center; line-height: 1;}
.pn-nps__score-value { font-size: 2.5em; font-weight: 700;}
.pn-nps__score-max { font-size: 1em; color: #aaaaaa;}
.pn-nps__screen--thanks { align-items: center; text-align: center; padding: 16px 0;}
.pn-nps__check-icon { width: 52px; height: 52px;}
.pn-nps__thanks { font-size: 0.95em; color: #444444; line-height: 1.6;}
.pn-nps__error { font-size: 0.8em; color: #cc0000; margin-top: -8px;}
.pn-nps__error--hidden { display: none;}Template JAVASCRIPT
本スクリプトは回答結果をPiano Audienceに送信するサンプルが含まれています
// 既存のコードを以下に置き換えるconst scores = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const [currentScreen, setCurrentScreen] = createSignal('score'); // 'score' | 'comment' | 'thanks'const [selectedScore, setSelectedScore] = createSignal(null);const [comment, setComment] = createSignal('');const [commentError, setCommentError] = createSignal('');
const selectScore = (score) => { setSelectedScore(score); setCurrentScreen('comment');};
const onSubmit = () => { if (!comment().trim()) { setCommentError('コメントを入力してください'); return; } setCommentError(''); sendSurveyData({ score: selectedScore(), comment: comment() }); setCookie("_pc_survey_closed", "true", 14); // 回答済みユーザーに14日間クッキーを保持。Composer設定と組み合わせて非表示設定可能 setCurrentScreen('thanks'); setTimeout(() => context.close(), 3000);};
// --- DMP push ---function sendSurveyData(data) { try { var customerPrefix = '/* お客様ごとに用意されているプレフィックスを指定してください */'; var persistedQueryId = '/* /dmp/push API用のpersistedQueryIdをご用意ください */'; cX.setEventAttributes({ origin: customerPrefix + "-survey", persistedQueryId: persistedQueryId }); cX.sendEvent("survey", data); } catch (e) { console.log(e); }}
function setCookie(cname, cvalue, exdays) { var d = new Date(); d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000)); var expires = "expires=" + d.toUTCString(); document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";}
function onCheckoutExternalEvent(event) { switch (event.eventName) { case 'close': setCookie("_pc_survey_closed", "true", 14); // 閉じたユーザーに14日間クッキーを保持。Composer設定と組み合わせて非表示設定可能 break; }}
tp.push(["addHandler", "checkoutCustomEvent", onCheckoutExternalEvent]);Template Content Fields
| コンテンツフィールド | 値(サンプル) | | --- | --- | | title | フィードバックのお願い | | question | このサービスを友人や同僚に勧める可能性はどのくらいですか? | | low_label | まったく勧めない | | high_label | 強く勧める | | comment_question | そう思う理由をお聞かせください(任意) | | comment_placeholder | ご意見・ご感想をご自由にお書きください | | submit_label | 送信する | | thanks_message | ご回答ありがとうございました! | | accent_color | 選択済みスコア・数字・チェックアイコンの色(例: #0066cc) | | close_color | 閉じるボタンの色(例: #999999) | | external_event_name | Piano Audience に送信するイベント名(例: nps_submit) |
Procedure - Experience
- Piano Activation にログインする
- 「プロダクト」メニュー → 「Composer」をクリック
- 右上の「作成」をクリック
- 「サイト用エクスペリエンス」を選択
- 任意の名称を設定し、右上の「作成」をクリック
- 任意の対象ページ、ユーザーセグメント、イベントを定義する
- アクションの「テンプレートを表示」カードを任意の条件の場所にドラッグ&ドロップする
- カードのプロパティを以下のように設定する
- テンプレート:先ほど作成したテンプレートを指定
- OPEN IN:モーダル/ライトボックス
- ユーザーがモーダルをクローズすることを許可:× ボタンは独自実装しているため、OFF にする
- ENCAPSULATION TYPE: Shadow DOM
- DESKTOP: ※必ず右の ADD ボタンから Mobile を追加して同じ設定をしてください
- POSITION: Center
- MAX SIZE: X 560px、Y 設定なし(コンテンツ高さに自動追従)
- MOBILE:
- POSITION: Center
- MAX SIZE: X 90vw、Y 設定なし
- ADDITIONAL SETTINGS:
- Page scroll enabled: ☑️
- Backdrop invisible: OFF
- Close on backdrop click: OFF(閉じるボタンで制御するため)
- キャンバス編集画面に戻り、保存をした後に「有効」をクリックしてバージョンをデプロイする
- Composer 画面に戻り、作成したエクスペリエンスを「ライブ」に設定する