catch-img

UTMパラメータをフォームの非表示項目に渡す方法

様々なWebマーケ施策に取り組むフェーズになると、最も顧客の獲得効率の良い集客チャネルや集客チャネル別の課題を分析するシーンが増えてきます。

特に、複数の広告などに出稿するシーンが増えてくると、「どの媒体が一番コンバージョンや商談につながっているんだろうか⋯」と悩むことがあるはずです。


ferret Oneの管理画面上では、チャネル別のCV件数の分析まではできますが、チャネル別の商談・受注貢献まで分析しようと思うと、リードごとの獲得チャネル(リードソース)をSFA側に渡す必要があります。

CVとともにチャネルや施策の情報をSalesforce等のSFAに送信ができれば、SFA上で各施策のROIが可視化され、より予算やリソースを最適な施策に配分することができるようになります。

Salesforceとferret Oneを連携したデータの管理に、お悩みの方はこちらの記事もぜひご参照ください。

  ferretのSalesforceダッシュボード公開!活用の鍵はマーケへのフィードバック? さまざまな指標があるインサイドセールス。他社がどのような数値を目標とし、どうやって進捗をチェックしているのか、気になる方も多いのではないでしょうか? そこで今回は、ferret のインサイドセールスが実際に使っている「Salesforceのダッシュボード」を大公開! インサイドセールスマネージャーに、進捗管理や運用のポイントをインタビューしました。 BtoBマーケティングのお困りごとをまるっと解決「ferret」



そこで今回は、フォーム送信時に流入チャネルの情報を取得することができる「UTMパラメータをフォームの非表示項目に渡す方法」をご紹介いたします。

※Javascriptの記述内容やカスタマイズは無償サポート範囲外となりますので、ご注意ください※


目次[非表示]

  1. 1.UTMパラメータとは?
  2. 2.実現するデータ送信の流れ
  3. 3.具体的な設定手順
    1. 3.1.1. Javascript埋め込みパーツの権限を開放する
    2. 3.2.2. Javascript埋め込みパーツを全ページに設置
    3. 3.3.3. フォーム項目に「非表示項目」を追加
  4. 4.注意点
  5. 5.まとめ

UTMパラメータとは?

UTMパラメータとは、URLの末尾につく文字列のことで、Webサイトを訪問したユーザーの流入経路を計測するために使用します。下記参考URLにある「?」以降の文字列がURLパラメータに当たります。URLパラメータを利用することで、ユーザーの流入経路を把握したり、Webにおける広告の効果測定などが可能となります。

例:


https://◯◯.co.jp/lp01/?utm_source=google&utm_medium=cpc&utm_campaign=marketin


UTMパラメータは、ferret Oneのキャンペーン機能で発行することができます。

(参考ヘルプページ:計測URLの発行手順)


実現するデータ送信の流れ

今回ご紹介するJavascriptを用いると、フォーム入力前にアクセスしたパラメータを非表示項目に渡すことができ、CVデータにチャネル情報を紐づけることができます。


<UTMパラメータを送信する仕組み>

  1. 各チャネル用にパラメータ付きURLを用意(参考:計測URLの設定
  2. ユーザーがアクセスすると、UTMパラメータの情報をcookieで保存
  3. フォーム送信時、保存したUTMパラメータを非表示項目に自動で入力され、CV情報として記録
  4. SFAやMAとAPI連携している場合:CV情報としてチャネル情報を送信


今回はチャネル別のパラメータを送信することを想定し、下記の3項目を非表示項目として作成し、各パラメータを送信する運用にしています。

  • utm_source:参照元(例:facebook)
  • utm_medium:メディア(例:ディスプレイ)
  • utm_campaign:キャンペーン(例:●●セミナー)


さらに、ferret Oneのフォームオートメーション機能を用いれば、フォームの非表示項目にあるパラメータに基づいたSalesforceキャンペーンの自動送信も可能です。


具体的な設定手順

今回の設定内容のポイントは、下記2点です。

  • JavaScriptを計測したい全ページに設置する
  • フォーム内に「非表示項目」という項目の準備が必要
    (Javascript内で非表示項目という項目を探すプログラムを組んでいるため)


実際の手順を下記で解説いたします。

1. Javascript埋め込みパーツの権限を開放する

Javascript埋め込みパーツの機能を初めてご利用になる場合は、テクニカルサポートデスクにご利用希望の旨をご連絡ください。無償で機能開放をさせていただきます。(テクニカルサポートの問い合わせフォーム)


2. Javascript埋め込みパーツを全ページに設置

以下のコードを、経路として想定しうるページ全てに設置をしてください。パラメータを付けたランディングページから、CVが発生するフォームのあるページまで、ユーザーが経由するページ全てが対象です。
基本的には、「共通フッター」に設置し、共通フッターがないページには個別に設置してください。

<script>
window.addEventListener('load', function () {
  "use strict";

  /** Cookieの値を取得する関数 */
  function getCookie(name) {
    const value = document.cookie.split('; ').find(row => row.startsWith(name + '='));
    return value ? decodeURIComponent(value.split('=')[1]) : null;
  }

  /** Cookieに値を保存する関数(maxAgeは保存秒数) */
  function setCookie(name, value, maxAgeSeconds) {
    document.cookie = name + '=' + encodeURIComponent(value) + '; max-age=' + maxAgeSeconds + '; path=/';
  }

  /** 現在の日本時間の日付(YYYY-MM-DD)を取得する関数 */
  function getTodayLocalDate() {
    const now = new Date();
    now.setMinutes(now.getMinutes() - now.getTimezoneOffset());
    return now.toISOString().slice(0, 10);
  }

  /** その日の0時までの残り時間(秒)を取得 */
  function getSecondsUntilEndOfDay() {
    const now = new Date();
    const endOfDay = new Date(now);
    endOfDay.setHours(23, 59, 59, 999);
    return Math.floor((endOfDay - now) / 1000);
  }

  /** 最初の訪問URLとその日付を記録(_fvurlに保存) */
  const currentDate = getTodayLocalDate();
  const existingFvurlRaw = getCookie('_fvurl');
  const existingFvurlParts = existingFvurlRaw ? existingFvurlRaw.split('___') : [];
  const existingUrl = existingFvurlParts[0];
  const existingDate = existingFvurlParts[1];
  const secondsToSave = Math.min(1800, getSecondsUntilEndOfDay());

  if (!existingUrl || existingDate !== currentDate) {
    const valueToSave = window.location.href + '___' + currentDate;
    setCookie('_fvurl', valueToSave, secondsToSave);
  }

  /** 記録したURLだけを取り出す(フォーム入力に使用) */
  const finalFvurl = getCookie('_fvurl');
  const savedURL = finalFvurl ? finalFvurl.split('___')[0] : null;
  if (savedURL) console.log("初回訪問URL:", savedURL);

  /** URLパラメータをオブジェクトとして取得(utm用) */
  function getUrlParams(url) {
    const params = {};
    if (!url) return params;
    const query = url.split('?')[1];
    if (!query) return params;
    query.split('&').forEach(pair => {
      const [key, value] = pair.split('=');
      if (key && value) params[decodeURIComponent(key)] = decodeURIComponent(value);
    });
    return params;
  }

  /** 対象フォームがあれば値を反映 */
  const contactForm = document.querySelector('form.contact_form');
  if (contactForm) {
    function updateHiddenFields() {
      const groups = document.querySelectorAll('.group');
      const params = getUrlParams(savedURL);

      /** 初回訪問URL → 「非表示項目」フィールドに入力 */
      let targetInputURL = null;
      groups.forEach(group => {
        const label = group.querySelector('label');
        if (label && label.textContent.includes('非表示項目')) targetInputURL = group.querySelector('input');
      });
      if (targetInputURL && savedURL) {
        const setValue = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
        setValue.call(targetInputURL, savedURL);
        targetInputURL.dispatchEvent(new Event('input', { bubbles: true }));
      }

      /** utm_source → 対応するフィールドに入力 */
      let targetInputSource = null;
      groups.forEach(group => {
        const label = group.querySelector('label');
        if (label && label.textContent.includes('utm_source')) targetInputSource = group.querySelector('input');
      });
      if (targetInputSource && params.utm_source) {
        const setValue = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
        setValue.call(targetInputSource, params.utm_source);
        targetInputSource.dispatchEvent(new Event('input', { bubbles: true }));
      }

      /** utm_medium → 対応するフィールドに入力 */
      let targetInputMedium = null;
      groups.forEach(group => {
        const label = group.querySelector('label');
        if (label && label.textContent.includes('utm_medium')) targetInputMedium = group.querySelector('input');
      });
      if (targetInputMedium && params.utm_medium) {
        const setValue = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
        setValue.call(targetInputMedium, params.utm_medium);
        targetInputMedium.dispatchEvent(new Event('input', { bubbles: true }));
      }

      /** utm_campaign → 対応するフィールドに入力 */
      let targetInputCampaign = null;
      groups.forEach(group => {
        const label = group.querySelector('label');
        if (label && label.textContent.includes('utm_campaign')) targetInputCampaign = group.querySelector('input');
      });
      if (targetInputCampaign && params.utm_campaign) {
        const setValue = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
        setValue.call(targetInputCampaign, params.utm_campaign);
        targetInputCampaign.dispatchEvent(new Event('input', { bubbles: true }));
      }
    }

    /** ページ読み込み時に実行 */
    updateHiddenFields();

    /** 動的にフォームが生成されても対応 */
    const observer = new MutationObserver(updateHiddenFields);
    observer.observe(document.body, { childList: true, subtree: true });
  }
});
</script>

参考)共通フッターの設置例

参考)共通フッターがないページの設置例

3. フォーム項目に「非表示項目」を追加

計測したいフォーム項目に、非表示項目を追加します。

  • 項目名:「utm_source」「utm_medium」「utm_campaign」
  • チェック:☑ この項目を非表示にする
  • 種類:テキスト(1行) ※「テキスト(複数行)」だとパラメータが入りません※



これで、パラメータのURLを非表示項目に自動入力できるようになります。設定が完了したら、テストCVでパラメータが正しく送信されているか確認してみましょう。
正しく送信されない場合は、Javascriptが設置されていないページがないかご確認ください。


注意点

  • Cookieを利用して情報を取得する方式を採用しております。そのため、Cookieポリシーに名称や利用目的などの記載が必要となる場合がございます。恐れ入りますが、各社のご判断・ご責任のもとでご確認いただけますようお願いいたします。
  • MAプランのSalesforceの顧客データ同期(双方向連携機能)をご利用の場合は、非表示項目をカスタム項目で作成し、Salesforce側にも項目を作成することでデータ送信が可能です。


まとめ

今回ご紹介した方法を活用すれば、1つのフォームで複数のチャネル情報を取得・分析することが可能になります。ぜひ、施策の分析にご活用ください!

Javascriptの記述内容やカスタマイズをご希望の際は、有償サポートでのみご相談を受け付けております。

▼有償サポートご相談受付フォーム
https://fo-keiyaku.hmup.jp/seisaku-gosoudan

今後ともferret Oneを宜しくお願いいたします。

大井 菜緒|ferret One CS
大井 菜緒|ferret One CS
2019年より株式会社ベーシックへ入社。インサイドセールスからフィールドセールスまでを経験し、2021年6月からカスタマーサクセス部へ異動。現在は顧客の戦略設計から伴走サポートまでを幅広く担当。ウェビナーやテックタッチの設計等も行う。
ページTOPへ戻るボタン