コンテンツマーケ運用メディア運用 / アクセス解析・計測

Microsoft Clarityのスクリーンショットが表示崩れする原因と対処|HTMLRewriterでstylesheetを保護する


Microsoft Clarity のヒートマップを開いたら、ナビが縦に並びロゴが巨大で、本文が裸の HTML のように見える──このとき疑うのは Strict マスキングです。個人情報保護のために href の値まで剥がしにかかるため、外部 CSS への参照が失われ、Clarity 側の再構築でスタイルが当たらなくなります。対処と、ハッシュ付き CSS が混ざる Vite / React Router 構成への一括適用方法までまとめます。

公開2026.05.20
最終更新2026.05.20
読了 7 分 / 約3,200字
この記事をシェアポスト
コンテンツマーケ運用開発ノウハウ

Clarityのスクショ崩れを
HTMLRewriterで直す

Microsoft Clarityのヒートマップを開くと、ナビが縦に積まれ、ロゴが巨大なまま、本文が裸のHTMLのように見える──通常のブラウザでは普通にスタイルが当たるのに、Clarity上だけ崩れる現象です。

本記事では、未スタイル表示の正体であるStrictマスキングによる stylesheet の href の消失と、`data-clarity-unmask="true"` での対処、ハッシュ付きCSSをビルダーに任せている構成(Vite / React Router / Webpack)への一括適用方法までを整理します。

C
結論
stylesheet の link タグに data-clarity-unmask="true" を付ければ直ります
  • 原因は、Clarity の既定「Strict」マスキングが<link rel="stylesheet">の href も剥がし、Clarity の DOM 再構築時に外部CSSを読めなくなることです。
  • 対処は、stylesheet の link にdata-clarity-unmask="true"を付けて href を守ることです。
  • Vite / React Router / Webpack のようにハッシュ付きCSSをビルダーが自動挿入する構成では、Cloudflare Workers の HTMLRewriter などで HTMLレスポンスの link[rel="stylesheet"] にまとめて属性を差し込むのが現実的です。

01.結論:stylesheetリンクに data-clarity-unmask="true" を付与する

Clarity のドキュメント Masking content にあるとおり、要素にdata-clarity-unmask="true"を付けると、その要素と配下のマスキングが解除されます。stylesheet の link に付ければ、href の値ごと守れます。

属性は、サーバーが返す HTML の段階で入れておくのが安全です。Cloudflare Workers / Next.js Middleware / Nginx の sub_filter など、HTML を書き換えられる層ならどこでも実装できます。本記事では弊社サイトで動かしている Cloudflare Workers + HTMLRewriter の実装を例にします。

02.症状の見分け方:未スタイル表示と単なる遅延の違い

Clarity のヒートマップを開けば一目で分かります。ナビが縦に積まれ、ロゴが等倍で大きく出て、本文は裸の HTML に近い見た目になります。下の例は弊社のサイトを Clarity で開いたところで、本来ブランド色と角丸が当たるヒーローカードが、巨大な暗色の楕円のように映っています。

Microsoft Clarity のヒートマップ画面で記事ページを開いたところ。ロゴが等倍で巨大に表示され、ナビゲーションが横一列に並ばず、ヒーローカードが角丸の楕円状の暗色シェイプとして再構築されている、未スタイル状態の例。
Clarity のヒートマップ画面の例。実ページではスタイルが当たっているのに、Clarity 側の再構築だけ未スタイルに見えている状態。

Clarity で「スタイルが崩れて見える」状態には、似て非なる症状が混ざります。Strict マスキング由来かを見分けるため、症状を切り分けます。

症状見え方想定される原因
未スタイルに見えるロゴが等倍で巨大、ナビが縦に並ぶ、ボタンが装飾なし、フォントが既定のままなど。CSSが効いていない裸のHTMLに近い本記事の対象。Strictマスキングが stylesheet の href まで消してしまっている
特定要素だけ抜けている見出しや本文の特定の箇所だけがブロック表示・伏字(□□□)Clarity の通常のテキストマスキング動作(個別の data-clarity-unmask で解除する)
ヒートマップだけが崩れているクリック分布などのオーバーレイは出るが、背景画像がブラウザ既定スタイル背景スクショが古いセッションのままで、修正版のセッションがまだ反映されていない(後述)
Clarityがそもそも読み込めないクリック・スクロールヒートマップに数字が入らない、レコーディングが0件タグ設置漏れ/Cookie同意未許可/ブラウザ拡張機能による遮断

本記事は1行目の「未スタイル」だけを扱います。2行目以降は別の設定で対処します。

03.原因:Strictマスキングは href の値まで消してしまう

Clarityは「DOMの再構築」でスクショを作る

Clarity は、ページの実画像をスクショとして保存しているわけではありません。タグ読み込み時に DOM と参照中のスタイルシート情報を取得し、Clarity 側のサーバーで再構築 してヒートマップ・レコーディングの背景を描画します。 Troubleshooting Heatmaps と Troubleshooting Recordings にも、「サイトのスタイリングアセットに Clarity がアクセスできる必要がある」と明記されています。

再構築時、HTML 中の<link rel="stylesheet" href="…">の href を読みに行き、CSSを取得して当てます。href が消えていれば CSS は取得できず、ブラウザ既定スタイルだけの描画になります。

Strictモードはデフォルトで全テキストと属性値をマスクする

Clarity は個人情報保護のためのマスキングを内蔵し、既定は「Strict」モードです。Strict モードは、入力欄の値だけでなく 本文テキスト・画像の alt・href / src のような属性値まで、PII に該当しうる箇所を一律にマスク します。マスクされた値は Clarity のサーバーに送られず、再構築時にも復元されません。

microsoft/clarity issue #124 にも、自動生成サイトで未スタイル表示になる事象が複数報告されています。Strict マスキングが stylesheet の href も対象に含めるため、Clarity がCSSを取得できなくなる挙動です。

i
補足
Strictを外す代わりに「stylesheetだけ unmask」する

「Strict を外せば直る」のは事実ですが、Strict は個人情報・機微情報の漏えいリスクを下げるための既定値です。サイト全体の masking 強度を下げるより、stylesheet だけを unmask するほうが、保護と表示を両立しやすい落としどころになります。

04.対処:data-clarity-unmask の付与パターン

静的に書いた link タグへの直接付与

Google Fonts や独自CDNなど、自分でHTMLに書ける link なら、属性を直接書き足すだけで終わります。

<link
  rel="stylesheet"
  href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100..900&display=swap"
  data-clarity-unmask="true"
/>

Clarity の Masking content が推奨するのもこの形です。属性が付いた要素と配下は、マスキングから除外されます。

Vite / Webpack が挿入するハッシュ付きCSSへの付与

モダンなフロントエンド構成では、CSS はビルドツールがハッシュ付きで吐き、HTML への link 挿入も任せます。Vite ならimport "./app.css"の解決結果として/assets/root-CjellP_l.cssのような URL が自動で差し込まれ、ハッシュはビルドごとに変わります。

この自動挿入された link タグに、ソースコードから直接属性を書く口はありません。React Router の<Links />や Next.js のnext/headは stylesheet 生成をフレームワーク側で担い、props で属性を差し込む公式 API は用意されていません。

現実的なのは、サーバーが返す HTML に対して、リバースプロキシ層・エッジ層で属性を一括で差し込む方針です。手段は環境によって変わります。

環境差し込み手段
Cloudflare Workers / Pages FunctionsHTMLRewriter で link[rel~="stylesheet"] を捕まえて setAttribute
Vercel / Netlify EdgeEdge Middleware の Response 書き換え(HTMLRewriter ライブラリやHTMLパーサ)
Next.js(自前ホスト含む)middleware.ts で NextResponse の HTML を書き換える、または next.config.js でheaders制御の代わりにserver側で文字列置換
Nginxngx_http_sub_module の sub_filter で href= を href= data-clarity-unmask="true" に置換
Apachemod_substitute で同様の文字列置換

次章では、弊社サイト(Cloudflare Workers + React Router 7 + Vite)で動かしている HTMLRewriter の実装を見ていきます。

05.Cloudflare Workers + HTMLRewriter の実装例

Cloudflare Workers の HTMLRewriter は、レスポンスHTMLをストリームのまま要素単位で書き換えできる組み込み API です。基盤は Cloudflare 製の Rust 製 HTMLパーサ lol-html で、Deno や Bun も同じ API を実装しており、エッジ系ランタイムでは事実上の共通インターフェースです。`/assets/...` のような静的アセットを誤って書き換えないよう、`response.ok` と Content-Type で text/html の 2xx だけを通します。

// Microsoft Clarity の Strict マスキングは link[rel="stylesheet"] の href を
// 剥がしてしまい、ヒートマップ/レコーディング画面でページが未スタイルに見える。
// data-clarity-unmask="true" を全 stylesheet リンクに付与し、href を保護する。
class StylesheetUnmasker {
  element(element: Element) {
    element.setAttribute("data-clarity-unmask", "true");
  }
}

export default {
  async fetch(request: Request, env: CloudflareEnvironment, ctx: ExecutionContext) {
    const response = await requestHandler(request, {
      cloudflare: { env, ctx },
    });

    if (
      response.ok &&
      response.headers.get("content-type")?.includes("text/html")
    ) {
      return new HTMLRewriter()
        .on('link[rel~="stylesheet"]', new StylesheetUnmasker())
        .transform(response);
    }
    return response;
  },
} satisfies ExportedHandler<CloudflareEnvironment>;

ポイントは4つです。

  • セレクタはlink[rel~="stylesheet"]を使う:~=は CSS の「空白区切りトークン一致」で、rel="preload stylesheet"やrel="modulepreload stylesheet"のような複数値 rel にもマッチする。完全一致の[rel="stylesheet"]だと複数値が漏れる。
  • preconnect / icon / modulepreload までは拾わない:「stylesheet を含む link」だけに絞り、関係ない link への属性差し込みを増やさない。
  • `response.ok` と Content-Type を併せてチェックする:4xx/5xx の HTML や text/html 以外まで HTMLRewriter に流すのを避ける。意図しないレスポンスへの変換は、パース失敗や挙動の読み違いの原因になる。
  • HTMLRewriter は変換結果を新しい Response として返す:ヘッダー(CSPやキャッシュ制御)は元から引き継がれ、別途の操作は不要。

実装後、`curl` で実 HTML を取得し、属性が付いたか確認します。

$ curl -s https://example.com/path | \
  grep -oE '<link[^>]*stylesheet[^>]*/>'

<link rel="stylesheet" href="/assets/root-XXXX.css" data-clarity-unmask="true" />
<link rel="stylesheet" href="https://fonts.googleapis.com/..." data-clarity-unmask="true" />

Vite が自動挿入するハッシュ付き CSS と、静的に書いた Google Fonts の両方に属性が付いていれば、Strict マスキングから保護される状態です。

!
注意
不要な属性をHTML全体に撒かない

セレクタをlink全部に広げると、favicon や preconnect など無関係な link にまで属性が付き、HTML が読みづらくなります。実際に CSS を引っ張る stylesheet だけに限定すれば必要十分です。

06.デプロイ後は時間をおいて確認する

デプロイ直後、Clarity ダッシュボードのスクショは古いHTMLから再構築されたままです。重要なのは、その場で正しいスクショを取り直す方法はない点です。Clarity のスクショは実際のユーザーセッションから自動で取得されるため、修正後の HTML を反映したスクショが現れるのは、修正版のページで新しいセッションが記録されたあとです。

ヒートマップ画面右上の「スクリーンショットを変更する」は、その場で撮り直すボタンではありません。 公式ドキュメント のとおり、Clarity が自動取得済みのスクショ群から別の状態を選び直す機能です。修正版のセッションがまだ溜まっていなければ、選択肢にも崩れたスクショしか並びません。デプロイ後すぐに直った状態を確認できるわけではないので、時間をおいて、新しいスクショが取得されてから確認するのが正しい運用です。

i
運用Tips
デプロイ後すぐは直って見えない。実セッションが溜まるのを待つ

スクショの更新には、修正版ページでの実ユーザーセッションが必要です。検証を早めたいときは、自分のブラウザで(Cookie 同意のうえ)修正版ページを実際に開いてセッションを発生させ、しばらく時間をおいてから「スクリーンショットを変更する」で新しい状態が選べるか確認します。

実際に弊社サイトでも、修正版を反映して時間をおいたあとに新しいスクショが取得され、ヒートマップが正しいスタイルで表示されるようになりました。

data-clarity-unmask 付与後の Microsoft Clarity ヒートマップ画面。ロゴ・ナビゲーション・ブランド色のヒーローカードがすべて正しいスタイルで再構築され、実ページと同じ見た目で表示されている。
修正後、新しいスクショが取得されたあとの Clarity ヒートマップ。stylesheet が読み込まれ、実ページと同じスタイルで表示されている。

Adding the attribute data-clarity-unmask="true" to an element unmasks that node and its children's contents, overriding anything set on the Clarity website.(要素に data-clarity-unmask="true" を付けると、その要素と配下の内容のマスキングを解除し、Clarity ダッシュボード側の設定よりも優先されます)

Microsoft Learn, Clarity – Masking content

07.まとめ

Clarity のヒートマップやレコーディングが未スタイルで表示される多くは、Strict マスキングが stylesheet の href を消し、Clarity 側で再構築できなくなっているケースです。スタイル自体が壊れているのではなく、Clarity に渡る HTML から外部 CSS への参照が消えているだけです。

対処は、stylesheet の link にdata-clarity-unmask="true"を付けること。静的に書いた link は属性を書き足すだけで終わり、ビルダーが挿入するハッシュ付き CSS は、Cloudflare Workers の HTMLRewriter のようなエッジ層の書き換えで一括して守るのがおすすめです。

サイト全体のマスキング強度を下げずに、表示の問題だけを直せます。未スタイル表示に悩んでいる場合は、まずブラウザの開発者ツール(Elements パネル)か HTML ソースで、stylesheet の link タグに `data-clarity-unmask` が付いているかを確認するところから始めてみてください。

関連記事

Cloudflare Workers のタイムアウトとサイズ制限を整理する

HTMLRewriterを含めCloudflare Workersをエッジで使うときに把握しておきたい、CPU時間・リクエスト本文サイズ・サブリクエスト数・メモリといった制限値を、公式ドキュメント基準でまとめています。

続きを読む
お問い合わせ

計測ツール導入・サイトインフラ設計のご相談はこちら

Microsoft Clarity・GA4 などの計測ツール導入、Cloudflare Workers / AWS Amplify などのSSR環境設計、品質管理を組み込んだ自動化運用までを支援しています。お気軽にお問い合わせください。

お問い合わせはこちら

メディア運用・コンテンツ制作 基礎知識集

一覧に戻る →
この記事をシェア
澤田 翔太(Shota Sawada)
この記事を書いた人

澤田 翔太

株式会社クリプタル 代表取締役

1988年生まれ、慶應義塾大学卒。創業メンバーとして関わった株式会社セールスサポートを株式会社ネオマーケティング(東証STD 4196)に売却。株式会社クリプタルでも複数の事業立ち上げと売却を経験し、2022年9月には婚活・恋愛メディア「シッテク」「婚活会議」を株式会社ベビーカレンダー(東証GRT 7363)へ売却。現在はAI業務支援事業、TANTOU事業、グロースハック支援事業、メディア事業、SEOコンサルティング事業を手がける。