要点
問い合わせフォームに営業メールを送ってくる人の大半は、弊社が何をしている会社かを見ていなかった。アクセスログを解析したところ、送信者の86%はサービス紹介にも制作実績にも一度も訪れていなかった。
そこで、送信内容をAIで判定する仕組みと、送信者がサイト内で何を見ていたかを記録する仕組みを作った。その記録から、営業送信には2種類あることが分かった。用意した文面を貼り付けて送る人と、ブラウザですらない自動送信ツールである。
後者はページのHTMLだけを取得し、CSSも画像も読み込まない。この特徴を手がかりに、機械からの送信を受け付けないようにした。
これは弊社自身のサイトでの取り組みである。お客様の環境ではなく自社を題材にしたので、ログの中身から実装まで包み隠さずに書ける。
きっかけ
問い合わせフォームに届く内容の多くが、営業・売り込みだった。弊社のフォームには、営業目的のご連絡はお受けしていない旨を明記している。それでも届く。
ここで疑問が残った。記載を読んだうえで無視しているのか、それともそもそも読んでいないのか。この2つは、対策の作り方がまったく違う。
読んだうえで無視しているなら、文面を強める意味がある。読んでいないなら、ページに何を書いても無駄で、受け取る側の仕組みを変えるしかない。感覚で決めずに、手元のデータで確かめることにした。
調べ方:アクセスログから送信者の足跡を復元する
新しい仕掛けは一つも不要だった。Webサーバーのアクセスログに、すでに必要な情報が残っていた。
ログは1行が1リクエストで、いつ・どのIPから・どのURLへ・何を要求されたかが並んでいる。問い合わせの送信も、特定のURLへの POST としてここに残る。これを起点にすればよい。
- ログ全体から、問い合わせ送信の POST を抜き出す
- それぞれについて、同じ IP からの直前のアクセスをさかのぼる
- その人が送信前に見ていたページと、滞在時間を並べる
- サービス紹介や制作実績のページを見たかどうかで分ける
対象は4月以降のアクセスログ、約1.6GB。これをコマンドと短いスクリプトで集計した。
この方法には限界がある。IP アドレスは固定とは限らず、同じ IP の向こうに複数人がいることもある。だから個々の送信を断定する目的ではなく、全体の傾向をつかむ目的で使っている。
分かったこと①:ほとんどの人はサービスを見ていない
疑問の答えははっきり出た。送信者の大半は、弊社が何を提供しているかを見ていない。
| 送信者の行動 | 割合・件数 |
|---|---|
| トップと問い合わせページしか見ていない | 86% |
| サービス紹介・制作実績まで見ている | 3% |
| フォームを開いてから10秒以内に送信 | 76件 |
| CSS・画像を一切読み込まずに送信 | 39件 |
86%という数字より、下の2行のほうが重要だった。
10秒以内の送信は、人が文章を考えて書く時間ではない。用意済みの文面を貼り付けている。さらにCSSや画像を読み込まない送信は、ブラウザではない何かが送っている可能性を示す。
この時点で、文面を強める方向は捨てた。読んでいない相手には、ページに何を書いても届かない。
仕組み①:AI判定と、動いていなかったフィルター
実は以前から、送信内容をAIで判定する仕組みを入れていた。そして、これが数か月間まったく機能していなかった。
ログを調べると、149件のうち142件が、AIの回答を一度も得ないまま「通常の問い合わせ」として素通りしていた。原因は2つあった。
- 提供が終了したモデルを呼び続けていた
- API からのエラー応答を検知していなかった
悪いのは2つ目だ。判定に失敗しても何も起きず、メールは普通に届く。外見上は正常に見えるため、壊れていることに気づけない。
作り直した際には、判定の精度と同じくらい「失敗に気づけること」を重視した。
- モデル名を管理画面から変更できるようにし、既定値を「常に最新を指す別名」にした(提供終了で止まらないように)
- 判定結果を JSON で受け取り、判定理由をメールとログに残す
- エラーを検知したら件名に印を付けて届け、直近のエラーを管理画面に表示する
- 管理画面に接続テストボタンを置く
営業と判定したものも破棄しない。件名の先頭に印を付けて届け、振り分けはメールソフトに任せる。誤判定で本物を失うほうが、営業メールを見る手間より高くつく。
過去の問い合わせ40件で検証したところ、判定できた30件はすべて正しく営業と判定された(残り10件は API の利用上限によるエラーで、判定の誤りではない)。
仕組み②:送信者の行動を記録する
判定の材料が本文だけでは足りなかった。ログ解析で分かった「読まずに送っている」という手がかりが、AI にも管理者にも渡っていなかった。
そこで、小さな JavaScript で次の4つを記録し、問い合わせと一緒に送るようにした。
- サイト内で見たページと、それぞれの滞在時間
- フォームのページを開いてから送信までの時間
- フォーム内のキー入力の回数と、貼り付けの回数
- どこから来たか(参照元)
記録は Contact Form 7 の隠しフィールドに入れて送る。このフィールドはプラグイン側から自動で追加されるので、フォームを編集する必要はない。受け取った内容は、管理者宛メールに添えると同時に、AI の判定材料にも使う。
プライバシーについても線を引いた。記録するのは自社サイト内の行動だけで、他サイトを追跡しない。入力欄に何を書いたかは記録せず、キーを押した回数だけを数える。収集している内容と目的は、プライバシーポリシーに明記した。
分かったこと②:営業送信には2つの型がある
記録が届き始めてすぐ、営業送信がすっきり2つの型に分かれることが分かった。
実際に届いた1件目はこうだった。
閲覧ページ(1件): /contact/
サービス・実績系ページの閲覧: 0件
フォームのページを開いてから送信まで: 28秒
フォーム内のキー入力: 7回/貼り付け: 2回
参照元: https://www.google.com/
キー入力7回で日本語の文章は書けない。貼り付け2回とあわせれば、用意済みの文面を貼って、残りを少し手で打った動きだと分かる。人は人だが、サイトは読んでいない。
もう一つの型は、記録そのものが空だった。JavaScript が一度も動いていない。そこで、その送信元をアクセスログで追った。
GET /contact/ ← HTML のみ取得
GET /contact/ ← 1秒後にもう一度
(20〜30秒待機)
POST /wp-json/contact-form-7/.../feedback
CSSも JavaScript も画像も、リクエストが1件もない。人がブラウザでページを開けば必ず発生する通信が、すっぽり抜けている。
もっとも目を引いたのは20〜30秒の待機だ。プログラムなら本来は1秒で送れる。わざわざ待っているのは、「送信が速すぎるものを弾く」よくある対策をすり抜けるためである。対策されていることを知ったうえで作られたツールだ。
この送信元からは、5月以降の約5か月で計6回の送信があった。他に、送信に至らないページ取得が5回。
| 型A:読まずに貼り付ける人 | 型B:自動送信ツール | |
|---|---|---|
| 見ているページ | 問い合わせページのみ | HTML を取得するだけ |
| CSS・画像 | 読み込む | 読み込まない |
| キー入力 | 数回(貼り付け中心) | 記録なし |
| 送信までの時間 | 数十秒 | 20〜30秒でほぼ一定 |
| 見分け方 | 記録の中身を読む | 記録が空であること自体 |
型A には、ページに何を書いても届かない。内容を読む AI の判定で仕分けるしかない。一方の型B は、行動記録が空だというそれ自体が手がかりになる。
仕組み③:ブラウザ以外からの送信を受け付けない
型B については、判定する前に送信自体を受け付けないことにした。行動記録のフィールドが空のまま送られてきたものを、スパム扱いとする。
ここで慎重になったのは、本物のお客様を弾いてしまうリスクだ。ブラウザの設定やセキュリティソフトで JavaScript を切っている方は、ほとんどいないがゼロではない。問い合わせを一件失う損失は、営業メールを何十件見る手間よりはるかに大きい。
そこで、ブロック自体よりも、その周りを厚く作った。
- ブロックした送信も消さずに記録として残す。後から本物が混ざっていないか確かめられる
- ブロック件数と直近の送信元を管理画面に表示し、気づけるようにする
- ブロックしたときは、送信者に「JavaScript を有効にしてください」と理由を伝える。原因が分からず諦めることを防ぐ
- フォームには、送信する前に気づけるよう注意書きを出す
- 万一問題が起きたら、コードを戻さずに機能だけを即座に止められるようにしておく
実装後、WordPress を立ち上げずに動かせる検証用の仕掛けを書き、20項目を確認した。フィールドが空・欠落・壊れた値のいずれもブロックし、通常のブラウザからの送信は——問い合わせページしか見ていない場合を含めて——ブロックしないことを確かめている。
これから測ること
仕組みを入れた時点では、まだ効果を語れない。測るのは次の4つで、数字が揃ったらこの記事に追記する。
- ブロックした送信の件数
- 営業判定が付いたメールの件数と、全体に占める割合の変化
- 誤判定・誤ブロックの件数(本物の問い合わせが混ざっていないか)
- 本物の問い合わせ1件にたどり着くまでに目を通す通数
最後の1つが、この取り組みの実際の効果にあたる。件数が減っても、探す手間が変わらなければ意味がない。
この事例から言えること
使ったデータは、すべて最初から手元にあった。足りなかったのは問いのほうだ。
アクセスログは何年も前から記録され続けていたが、誰も見ていなかった。「送信者は本当にサイトを読んでいるのか」と具体的に問いを立てた瞬間に、同じログが答えに変わった。DX の相談でも、「データがない」と思われているものが、実は問いがないだけということは多い。
2つ目は、壊れていることに気づける作りにすること。AI 判定は数か月間失敗し続けていたが、メールは普通に届いていたため、外からは正常に見えていた。黙って失敗する仕組みは、ある意味で、はっきり止まる仕組みよりたちが悪い。
3つ目は、対策を相手側ではなく自分側に置くこと。読まない相手に注意書きは届かない。相手の行動を変えようとするより、受け取る側で仕分けるほうが確実だった。
送信元の社名を公開する案も検討したが、見送った。注意書きを読まない相手には予告も読まれず抑止にならないこと、フォームの社名欄は検証できないためなりすましで無関係の会社を巻き込む危険があること、そして晒しリストは掲載する側の印象を損ねることが理由だ。
ここで踏んだ手順は、問い合わせフォームに限った話ではない。現状をログで把握し、仮説を立て、小さく実装し、効果を測る。弊社が DX 支援でお手伝いしているのは、この繰り返しである。
この取り組みは、図付きで制作実績にもまとめています。