WithCodeMedia-1-pc
previous arrowprevious arrow
next arrownext arrow

WithCodeMedia-1-sp
previous arrowprevious arrow
next arrownext arrow

【SEO完全ガイド】構造化データをJavaScriptで動的生成する方法を徹底解説

生徒

博士、構造化データを実装したいんですけど、WordPressやCMSのテンプレートを直接編集できない場合はどうすればいいですか?

ペン博士

よーく聞くんだぞ。今日はJavaScriptで構造化データを動的生成する方法について詳しく解説するぞい!テンプレート編集なしで実装できるんじゃ!

生徒

そうなんですか!?ぜひ教えてください!

構造化データは、検索エンジンにWebページの内容を正確に伝えるための重要な仕組みです。通常はHTMLに直接記述しますが、テンプレートファイルを編集できない環境や、ページごとに異なるデータを動的に挿入したい場合、JavaScriptでの実装が有効です。

本記事では、JavaScriptを使った構造化データの動的生成方法を、Google公式のガイドラインに基づいて詳しく解説します。Google Tag Manager、カスタムJavaScript、実装のベストプラクティスまで網羅しています。

「学習→収入」につなげた受講生のリアルな体験談も公開中!
働き方を変えたい方にも響くストーリーです。

堀さん
働く場所や時間に縛られない生活を送りたいと考え、独学でプログラミング学習を開始するもレベルの差を感じ、WithCodeに入会されました。カリキュラムを進めた結果、見事卒業テストを合格し、現在は、WithCode Platinumで副業として案件を担当しています。

詳しくはこちらの記事をご覧ください。

堀さんの主な制作実績はこちら


目次

構造化データとは?

構造化データ(Structured Data)は、Webページの内容を検索エンジンが理解しやすい形式でマークアップしたデータです。Schema.orgという標準規格に基づいて記述し、JSON-LD、Microdata、RDFaなどの形式で実装します。

構造化データのメリット

  • リッチリザルトの表示:検索結果に星評価、価格、画像などが表示される
  • クリック率(CTR)の向上:視覚的に目立つため、クリックされやすい
  • 音声検索への対応:Google AssistantやAlexaが情報を読み上げやすい
  • ナレッジグラフへの表示:Googleのナレッジパネルに情報が表示される可能性

主要な構造化データタイプ

  • Article:ブログ記事、ニュース記事
  • Product:商品情報、価格、在庫
  • Recipe:レシピ、調理時間、材料
  • Event:イベント、日時、場所
  • Organization:会社情報、ロゴ、SNS
  • LocalBusiness:店舗情報、営業時間、住所
  • FAQPage:よくある質問
  • BreadcrumbList:パンくずリスト

なぜJavaScriptで動的生成するのか?

生徒

HTMLに直接書くのではなく、JavaScriptで生成する理由は何ですか?

ペン博士

テンプレート編集が難しい場合や、動的なデータを扱う場合に便利なんじゃ!

JavaScriptで動的生成するメリット

1. テンプレート編集が不要

WordPress、Shopify、WixなどのCMSでは、テーマやテンプレートファイルに直接アクセスできない場合があります。特に企業サイトやECサイトでは、開発会社がテーマを管理しており、マーケティング担当者が自由にコードを編集できないケースも珍しくありません。

そのような環境でも、JavaScriptを使えばページに構造化データを追加できます。例えば Google Tag Manager(GTM) を利用すれば、CMSのテンプレートを変更せずに<script type="application/ld+json"> を動的に挿入可能です。

この方法を使えば、

  • CMSのテーマを変更せずにSEO改善ができる
  • 開発者の作業を待たずにマーケティング施策を実行できる
  • 外部スクリプトとして管理できるためメンテナンスが容易

といったメリットがあります。特に大規模サイトでは、テンプレート改修よりもGTMでの実装のほうが運用コストを抑えられる場合があります。

2. ページごとに異なるデータを自動挿入

JavaScriptを使う大きな利点のひとつが、ページごとに異なる情報を自動取得して構造化データに反映できる点です。

例えば次のようなケースです。

  • 商品ページ → 商品名・価格・在庫状況
  • ブログ記事 → 記事タイトル・公開日・著者
  • レビュー記事 → 評価スコア・レビュー数

JavaScriptでDOMから情報を取得すれば、

document.querySelector('.product-price').textContent

のように、ページに表示されているデータをそのまま構造化データへ反映できます。

これにより、

  • 商品ページが数千ページある場合でも自動生成できる
  • CMSのデータ構造に依存せず実装できる
  • 手動入力によるミスを防げる

といったメリットがあります。

3. A/Bテストが容易

構造化データはSEOに影響する要素ですが、実際の効果はサイトや検索クエリによって異なります。JavaScriptで生成する場合、Google Tag Managerなどを使ったA/Bテストが容易になるという利点があります。

例えば以下のようなテストが可能です。

  • 構造化データあり / なしの比較
  • FAQ構造化データの表示有無
  • Productマークアップの追加有無

これにより、

  • CTR(クリック率)の変化
  • 検索結果のリッチリザルト表示率
  • インデックスの変化

などを検証できます。

SEO施策は「実装して終わり」ではなく、「効果検証 → 改善」が重要です。JavaScript実装は、この検証サイクルを高速化できる点が強みです。

4. 複数サイトで再利用可能

JavaScriptで構造化データ生成スクリプトを作成しておけば、同じコードを複数のWebサイトで再利用できます。

例えば以下のようなケースです。

  • 複数ブランドを運営している企業サイト
  • 同じCMSテンプレートを使っているサイト群
  • 複数のECサイト

一度作ったスクリプトをGTMや外部JavaScriptとして配布すれば、各サイトに簡単に導入できます。

これにより、

  • 実装コストの削減
  • SEO施策の標準化
  • 更新管理の簡略化

が可能になります。

JavaScriptで動的生成するデメリット

1. クロール頻度の低下(Productマークアップ)

Googleの公式ドキュメントでは、Product構造化データをJavaScriptで動的生成する場合、クロール頻度が低下する可能性があるとされています。

特にECサイトでは、

  • 価格変更
  • 在庫変動
  • セール情報

などが頻繁に更新されます。

もし構造化データがJavaScriptで生成されている場合、Googleがその情報を取得するためにページレンダリング(JavaScript実行) を行う必要があります。その結果、クロールの優先度が下がる場合があります。

そのためGoogleは、

  • 価格
  • 在庫
  • 商品情報

などの重要なProductデータは、サーバーサイドレンダリング(HTML内に直接記述)を推奨しています。

2. JavaScriptの実行が必要

GoogleはJavaScriptを実行してページをレンダリングすることができますが、その処理は二段階インデックスで行われます。

  1. HTMLをクロール
  2. JavaScriptを実行してレンダリング

この仕組みのため、

  • JavaScript実行が遅い
  • 外部スクリプトがブロックされる
  • レンダリング待ちキューに入る

といった場合、構造化データの認識が遅れる可能性があります。

特に以下の環境では注意が必要です。

  • 外部スクリプト依存が多いサイト
  • 大規模ECサイト
  • JavaScriptが重いSPAサイト

3. デバッグが複雑

HTML内に直接構造化データを書く場合は、ソースコードを見ればすぐに確認できます。しかしJavaScriptで生成する場合、どのタイミングでスクリプトが実行されるのかを理解する必要があります。

例えば以下のような問題が発生することがあります。

  • DOM取得タイミングのズレ
  • JavaScriptエラーでJSON-LDが生成されない
  • 非同期処理で値が取得できない

その結果、

  • 構造化データが出力されない
  • 不正なJSONが生成される
  • Rich Results Testで検出されない

といったトラブルにつながることがあります。
そのため実装後は必ず

  • Google Rich Results Test
  • Schema Markup Validator
  • Search Console

などのツールで検証することが重要です。


実装方法1:Google Tag Managerを使った動的生成

生徒

具体的な実装方法を知りたいです!

ペン博士

うむ。まずはGoogle Tag Manager(GTM)を使った方法じゃ!Google Tag Manager(GTM)は、コードを直接編集せずにタグを管理できるツールじゃ。構造化データの実装にも非常に便利じゃぞ!

ステップ1:Google Tag Managerのセットアップ

  1. Google Tag Manager(https://tagmanager.google.com/)にアクセス
  2. アカウントとコンテナを作成
  3. Webサイトの<head><body>にGTMスニペットを追加

ステップ2:変数の設定

ページから情報を取得するための変数を設定します。

  1. GTM管理画面で「変数」→「新規」をクリック
  2. 「変数タイプ」で「DOM要素」または「JavaScript変数」を選択
  3. 取得したい要素のセレクタを指定

例:記事タイトルを取得する変数

  • 変数名: articleTitle
  • 変数タイプ: DOM要素
  • 選択方法: CSSセレクタ
  • 要素セレクタ: h1.article-title
  • 属性名: textContent

ステップ3:カスタムHTMLタグの作成

1. GTM管理画面で「タグ」→「新規」をクリック

2. 「タグタイプ」で「カスタムHTML」を選択

3. 以下のコードを入力

<script>
// 構造化データの作成
var structuredData = {
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "{{articleTitle}}", // GTM変数を使用
  "author": {
    "@type": "Person",
    "name": "{{authorName}}"
  },
  "datePublished": "{{publishDate}}",
  "dateModified": "{{modifiedDate}}",
  "image": "{{articleImage}}",
  "publisher": {
    "@type": "Organization",
    "name": "WithCode",
    "logo": {
      "@type": "ImageObject",
      "url": "https://withcode.tech/logo.png"
    }
  },
  "description": "{{articleDescription}}"
};

// script要素を作成
var script = document.createElement('script');
script.type = 'application/ld+json';
script.text = JSON.stringify(structuredData);

// headに追加
document.head.appendChild(script);
</script>

ステップ4:トリガーの設定

  1. 「トリガー」で「すべてのページ」を選択(全ページで実行)
  2. または「ページビュー – DOM Ready」を選択(DOMが読み込まれた後に実行)

ステップ5:公開

  1. 「プレビュー」で動作確認
  2. 問題なければ「公開」をクリック

実装方法2:カスタムJavaScriptで動的生成

ペン博士

次は、GTMを使わずに、独自のJavaScriptコードで構造化データを生成する方法じゃ!こちらも覚えておくと非常に便利じゃぞ!

生徒

へえー、そういうこともできるんですね!はい、お願いします!

基本的な実装例:Article(記事)

// DOMが読み込まれた後に実行
document.addEventListener('DOMContentLoaded', function() {
  // ページから情報を取得
  const title = document.querySelector('h1.article-title')?.textContent;
  const author = document.querySelector('.author-name')?.textContent;
  const publishDate = document.querySelector('time[itemprop="datePublished"]')?.getAttribute('datetime');
  const modifiedDate = document.querySelector('time[itemprop="dateModified"]')?.getAttribute('datetime');
  const image = document.querySelector('meta[property="og:image"]')?.getAttribute('content');
  const description = document.querySelector('meta[name="description"]')?.getAttribute('content');

  // 構造化データを作成
  const structuredData = {
    "@context": "https://schema.org",
    "@type": "Article",
    "headline": title,
    "author": {
      "@type": "Person",
      "name": author
    },
    "datePublished": publishDate,
    "dateModified": modifiedDate || publishDate,
    "image": image,
    "publisher": {
      "@type": "Organization",
      "name": "WithCode",
      "logo": {
        "@type": "ImageObject",
        "url": "https://withcode.tech/logo.png"
      }
    },
    "description": description,
    "mainEntityOfPage": {
      "@type": "WebPage",
      "@id": window.location.href
    }
  };

  // script要素を作成してheadに追加
  const script = document.createElement('script');
  script.type = 'application/ld+json';
  script.textContent = JSON.stringify(structuredData, null, 2); // 読みやすいように整形
  document.head.appendChild(script);
});

応用例:Product(商品)

document.addEventListener('DOMContentLoaded', function() {
  // 商品情報を取得
  const productName = document.querySelector('.product-name')?.textContent;
  const productImage = document.querySelector('.product-image img')?.src;
  const productPrice = document.querySelector('.product-price')?.textContent.replace(/[^0-9]/g, '');
  const productCurrency = 'JPY';
  const productAvailability = document.querySelector('.in-stock') ? 'InStock' : 'OutOfStock';
  const productSKU = document.querySelector('[data-sku]')?.dataset.sku;
  const productRating = document.querySelector('.rating-value')?.textContent;
  const productReviewCount = document.querySelector('.review-count')?.textContent;

  const structuredData = {
    "@context": "https://schema.org",
    "@type": "Product",
    "name": productName,
    "image": productImage,
    "description": document.querySelector('.product-description')?.textContent,
    "sku": productSKU,
    "offers": {
      "@type": "Offer",
      "url": window.location.href,
      "priceCurrency": productCurrency,
      "price": productPrice,
      "availability": `https://schema.org/${productAvailability}`,
      "priceValidUntil": new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString().split('T')[0] // 30日後
    }
  };

  // 評価がある場合のみ追加
  if (productRating && productReviewCount) {
    structuredData.aggregateRating = {
      "@type": "AggregateRating",
      "ratingValue": productRating,
      "reviewCount": productReviewCount
    };
  }

  const script = document.createElement('script');
  script.type = 'application/ld+json';
  script.textContent = JSON.stringify(structuredData, null, 2);
  document.head.appendChild(script);
});

応用例:BreadcrumbList(パンくずリスト)

document.addEventListener('DOMContentLoaded', function() {
  // パンくずリストの要素を取得
  const breadcrumbItems = document.querySelectorAll('.breadcrumb-item');

  if (breadcrumbItems.length === 0) return;

  // パンくずリストの配列を作成
  const itemListElement = Array.from(breadcrumbItems).map((item, index) => {
    const link = item.querySelector('a');
    return {
      "@type": "ListItem",
      "position": index + 1,
      "name": item.textContent.trim(),
      "item": link ? link.href : window.location.href
    };
  });

  const structuredData = {
    "@context": "https://schema.org",
    "@type": "BreadcrumbList",
    "itemListElement": itemListElement
  };

  const script = document.createElement('script');
  script.type = 'application/ld+json';
  script.textContent = JSON.stringify(structuredData, null, 2);
  document.head.appendChild(script);
});

実装のベストプラクティス

生徒

JavaScriptで構造化データを生成するときの注意点はありますか?

ペン博士

Google公式のベストプラクティスに従うことが重要じゃ!

1. 既存のHTMLから変数を抽出する

生徒

JavaScriptで構造化データをうまく実装するためにはどうしたら良いですか?

ペン博士

良い質問じゃ。ここでは、プロフェッショナルな実装をするための6つの方法を紹介するぞ!

1. 既存のHTMLから変数を抽出する

情報を重複させず、既存のHTML要素から動的に取得します。

// 良い例:既存要素から取得
const title = document.querySelector('h1')?.textContent;

// 悪い例:ハードコーディング
const title = "商品タイトル";

2. DOMContentLoadedイベントを使用

DOMが完全に読み込まれた後に実行することで、要素が確実に存在する状態で処理できます。

document.addEventListener('DOMContentLoaded', function() {
  // 構造化データの生成処理
});

3. オプショナルチェーン(?.)を使用

要素が存在しない場合のエラーを防ぎます。

// 良い例:要素がなくてもエラーにならない
const author = document.querySelector('.author')?.textContent;

// 悪い例:要素がないとエラー
const author = document.querySelector('.author').textContent;

4. 必須プロパティを必ず含める

各構造化データタイプには、必須プロパティがあります。Googleのドキュメントで確認しましょう。

例:Articleの必須プロパティ

  • headline(記事タイトル)
  • image(画像URL)
  • datePublished(公開日)
  • author(著者)

5. サーバーサイドレンダリング(SSR)も検討

特にProductマークアップでは、JavaScriptよりもサーバーサイドレンダリングが推奨されます。Next.jsやNuxt.jsなどのフレームワークを使用すると、SSRが簡単に実装できます。

6. 複数の構造化データを組み合わせる

1つのページに複数の構造化データを配置できます。

// Articleと BreadcrumbListを両方追加
const articleData = { "@type": "Article", ... };
const breadcrumbData = { "@type": "BreadcrumbList", ... };

// それぞれ別のscript要素として追加
const script1 = document.createElement('script');
script1.type = 'application/ld+json';
script1.textContent = JSON.stringify(articleData);
document.head.appendChild(script1);

const script2 = document.createElement('script');
script2.type = 'application/ld+json';
script2.textContent = JSON.stringify(breadcrumbData);
document.head.appendChild(script2);

テストと検証

ペン博士

他にもテストや検証する方法もあるから覚えておくのじゃぞ!

生徒

はい、わかりました!よろしくお願いします!

1. リッチリザルトテスト

Googleの公式ツール「リッチリザルトテスト」で、構造化データが正しく認識されるか確認します。

  1. リッチリザルトテスト(https://search.google.com/test/rich-results)にアクセス
  2. URLをテストを選択(推奨)
  3. テストしたいページのURLを入力
  4. 「URLをテスト」をクリック

注意: コードスニペットを直接入力する方法もありますが、JavaScriptで動的生成する場合はCORS制限により正しく動作しないことがあります。URLを入力する方法を使用しましょう。

2. Schema Markup Validator

Schema.org公式のバリデーターでも検証できます。

  1. Schema Markup Validator(https://validator.schema.org/)にアクセス
  2. URLまたはコードを入力
  3. 「Validate」をクリック

3. ブラウザの開発者ツールで確認

実装後、ブラウザの開発者ツールで<head>内に構造化データが追加されているか確認します。

  1. ページを開く
  2. F12キーで開発者ツールを開く
  3. 「Elements」タブで<head>内を確認
  4. <script type="application/ld+json">が追加されているか確認

トラブルシューティング

生徒

JavaScriptの構造化データを実装するにあたってトラブルシューティングのことも知りたいです!

ペン博士

む。ここでは、主なトラブルシューティングを3つ紹介するぞい!

問題1: 構造化データが認識されない

原因と解決法:

  • JavaScriptの実行タイミングが遅いDOMContentLoadedイベントを使用
  • 要素が取得できていない → セレクタを確認、オプショナルチェーン(?.)を使用
  • JSON形式が不正JSON.stringify()を使用して正しい形式に

問題2: リッチリザルトテストでエラーが出る

原因と解決法:

  • 必須プロパティが不足 → Googleのドキュメントで必須項目を確認
  • プロパティの型が間違っている → 文字列、数値、配列など正しい型を使用
  • 日付の形式が不正 → ISO 8601形式(YYYY-MM-DD)を使用

問題3: 動的に生成した構造化データが検索結果に反映されない

原因と解決法:

  • Googleのクロールを待つ → 反映まで数日〜数週間かかる場合がある
  • Google Search Consoleで再クロールをリクエスト → URL検査ツールを使用
  • ページの品質を改善 → コンテンツの質が低いとリッチリザルトが表示されない

Next.jsでの実装例(サーバーサイドレンダリング)

ペン博士

実は、サーバーサイドでも構造化データを生成できる方法がある。これも覚えておくと非常に便利じゃぞ!

生徒

そうなんですね!勉強になります!

Next.jsを使えば、サーバーサイドで構造化データを生成できます。これはJavaScriptでの動的生成よりも推奨される方法です。

// pages/articles/[slug].tsx
import Head from 'next/head';
export default function ArticlePage({ article }) {
  const structuredData = {
    "@context": "https://schema.org",
    "@type": "Article",
    "headline": article.title,
    "author": {
      "@type": "Person",
      "name": article.author
    },
    "datePublished": article.publishedAt,
    "dateModified": article.updatedAt,
    "image": article.coverImage,
    "publisher": {
      "@type": "Organization",
      "name": "WithCode",
      "logo": {
        "@type": "ImageObject",
        "url": "https://withcode.tech/logo.png"
      }
    },
    "description": article.description
  };
  return (
    <>
      
        

生徒

JavaScriptで構造化データを動的生成する方法がよく分かりました!まずはGoogle Tag Managerで試してみます!

ペン博士

その通りじゃ!GTMならコードを書かずに実装できるから、初心者にもおすすめじゃぞ!実装後は必ずリッチリザルトテストで検証するんじゃ!

生徒

はい!次のプロジェクトでブログ記事に構造化データを実装してみます!ありがとうございました!


まとめ

本記事では、JavaScriptを使った構造化データの動的生成方法について、Google公式のガイドラインに基づいて詳しく解説しました。

重要なポイントは以下の通りです。

・構造化データのメリット:リッチリザルト表示、CTR向上、音声検索対応
・実装方法:Google Tag Manager、カスタムJavaScript、サーバーサイドレンダリング
・推奨方法:初心者はGTM、カスタマイズが必要ならJavaScript、本番環境ではSSR
・ベストプラクティス:既存HTML から変数抽出、DOMContentLoaded使用、必須プロパティを含める
・テスト方法:リッチリザルトテスト、Schema Markup Validator、開発者ツール
・注意点:Productマークアップは動的生成でクロール頻度が低下する可能性

WithCodeで学んだHTML・CSS・JavaScriptの基礎知識に、構造化データの実装技術を組み合わせれば、どんな実案件でもSEO最適化されたWebサイトを構築できます。

構造化データは、SEOにおいて非常に重要な要素です。ぜひ実際のプロジェクトで活用し、検索結果での視認性を向上させてください。


WithCodeを体験できる初級コース公開中!

初級コース(¥49,800)が完全無料に!

  • 期間:1週間
  • 学習内容:
    ロードマップ/基礎知識/環境構築/HTML/CSS/LP・ポートフォリオ作成
    → 正しい学習方法で「確かな成長」を実感できるカリキュラム

副業・フリーランスが主流になっている今こそ、自らのスキルで稼げる人材を目指してみませんか?

未経験でも心配することはありません。初級コースを受講される方の大多数はプログラミング未経験です。まずは無料カウンセリングで、悩みや不安をお聞かせください!

この記事を書いた人

WithCode(ウィズコード)は「目指すなら稼げる人材」をビジョンに、累計400名以上のフリーランスを輩出してきた超実践型プログラミングスクールです。150社以上の実案件支援を特徴にWeb制作・Webデザインなどの役立つ情報を現場のノウハウに基づいて発信していきます。

– service –WithCodeの運営サービス

  • WithCode
    - ウィズコード -

    スクール

    「未経験」から
    現場で通用する
    スキルを身に付けよう!

    詳細はこちら
  • WithFree
    - ウィズフリ -

    実案件サポート

    制作会社のサポート下で
    実務経験を積んでいこう!

    詳細はこちら
  • WithCareer
    - ウィズキャリ -

    就転職サポート

    大手エージェントのサポート下で
    キャリアアップを目指そう!

    詳細はこちら

公式サイト より
今すぐ
無料カウンセリング
予約!

目次