Astro calendar_today 23 апр. 2026 г. schedule 2 мин

Structured Data и JSON-LD в Astro: Разметка для Google

Полное руководство по JSON-LD structured data в Astro: Article, BreadcrumbList, FAQPage, Product, Person, Organization. Как проверить разметку и что даёт в поиске.

person
Журналист
Автор
Structured Data JSON-LD в Astro — разметка для Google

Structured Data (структурированные данные) — это разметка, которая объясняет Google, что именно находится на странице. В ответ Google показывает rich results: звёздочки рейтинга, цены, FAQ прямо в выдаче. Astro упрощает добавление JSON-LD до нескольких строк.

Что такое Rich Results и зачем они нужны

Rich results — расширенные результаты поиска с дополнительными элементами:

  • Статья → дата, автор, обложка в Google Discover
  • Продукт → цена, наличие, рейтинг прямо под ссылкой
  • FAQ → раскрываемые вопросы и ответы в выдаче
  • Хлебные крошки → путь к странице вместо URL
  • Персона → фото и должность в Knowledge Panel
  • Организация → логотип, контакты в выдаче

CTR у rich results на 20-30% выше обычных результатов.

Базовый компонент JsonLd

code
---
// src/components/JsonLd.astro
interface Props {
  schema: Record<string, unknown> | Record<string, unknown>[];
}

const { schema } = Astro.props;
---

<script type="application/ld+json" set:html={JSON.stringify(schema, null, 0)} />

Используйте в любом месте страницы — лучше в <head> или в конце <body>:

code
---
import JsonLd from '../components/JsonLd.astro';
---

<JsonLd
  schema={{ '@context': 'https://schema.org', '@type': 'WebSite', name: 'Мой сайт' }}
/>

Схема: Article (статьи блога)

Самая нужная схема для контентных сайтов:

code
---
// src/pages/articles/[slug].astro
import JsonLd from '../../components/JsonLd.astro';

const { article } = Astro.props;

const articleSchema = {
  '@context': 'https://schema.org',
  '@type': 'Article',
  headline: article.data.title,
  description: article.data.description,
  datePublished: article.data.date.toISOString(),
  dateModified: article.data.date.toISOString(),
  author: {
    '@type': 'Person',
    name: article.data.author ?? 'Редакция',
    url: new URL('/about', Astro.site).href,
  },
  publisher: {
    '@type': 'Organization',
    name: 'Название сайта',
    logo: {
      '@type': 'ImageObject',
      url: new URL('/logo.png', Astro.site).href,
    },
  },
  image: article.data.cover
    ? new URL(`/og/${article.id.replace('.mdx', '')}.png`, Astro.site).href
    : undefined,
  url: Astro.url.href,
  mainEntityOfPage: {
    '@type': 'WebPage',
    '@id': Astro.url.href,
  },
};
---

<JsonLd schema={articleSchema} />

Схема: BreadcrumbList (хлебные крошки)

code
---
// src/components/Breadcrumbs.astro
interface Crumb {
  label: string;
  href: string;
}

interface Props {
  crumbs: Crumb[];
}

const { crumbs } = Astro.props;

const schema = {
  '@context': 'https://schema.org',
  '@type': 'BreadcrumbList',
  itemListElement: crumbs.map((crumb, i) => ({
    '@type': 'ListItem',
    position: i + 1,
    name: crumb.label,
    item: new URL(crumb.href, Astro.site).href,
  })),
};
---

<nav aria-label="Навигация по сайту">
  <ol>
    {
      crumbs.map((crumb, i) => (
        <li>
          {i < crumbs.length - 1 ? (
            <a href={crumb.href}>{crumb.label}</a>
          ) : (
            <span aria-current="page">{crumb.label}</span>
          )}
          {i < crumbs.length - 1 && <span aria-hidden="true">›</span>}
        </li>
      ))
    }
  </ol>
</nav>

<script type="application/ld+json" set:html={JSON.stringify(schema)} />

Использование на странице статьи:

code
<Breadcrumbs
  crumbs={[
    { label: 'Главная', href: '/' },
    { label: 'Статьи', href: '/articles/' },
    { label: article.data.title, href: Astro.url.pathname },
  ]}
/>

Схема: FAQPage

FAQ-разметка раскрывает вопросы и ответы прямо в выдаче Google — мощный инструмент для информационных страниц:

code
---
// src/components/FAQ.astro
interface FAQItem {
  question: string;
  answer: string;
}

interface Props {
  items: FAQItem[];
}

const { items } = Astro.props;

const schema = {
  '@context': 'https://schema.org',
  '@type': 'FAQPage',
  mainEntity: items.map((item) => ({
    '@type': 'Question',
    name: item.question,
    acceptedAnswer: {
      '@type': 'Answer',
      text: item.answer,
    },
  })),
};
---

<section>
  <h2>Частые вопросы</h2>
  {
    items.map((item) => (
      <details>
        <summary>{item.question}</summary>
        <p>{item.answer}</p>
      </details>
    ))
  }
</section>

<script type="application/ld+json" set:html={JSON.stringify(schema)} />

Использование в MDX:

code
import FAQ from '../../components/FAQ.astro';

<FAQ
  items={[
    {
      question: 'Нужен ли Node.js для Astro?',
      answer:
        'Для разработки — да. В продакшне Astro генерирует статические HTML-файлы, Node.js не нужен.',
    },
    {
      question: 'Можно ли использовать React в Astro?',
      answer:
        'Да, React-компоненты работают как острова через @astrojs/react интеграцию.',
    },
  ]}
/>

Схема: Product (интернет-магазин)

code
---
const productSchema = {
  '@context': 'https://schema.org',
  '@type': 'Product',
  name: product.data.title,
  description: product.data.description,
  sku: product.data.sku,
  brand: {
    '@type': 'Brand',
    name: 'Название бренда',
  },
  image: product.data.cover ? [coverUrl] : undefined,
  offers: {
    '@type': 'Offer',
    priceCurrency: 'RUB',
    price: (product.data.price / 100).toFixed(2),
    availability: product.data.inStock
      ? 'https://schema.org/InStock'
      : 'https://schema.org/OutOfStock',
    seller: {
      '@type': 'Organization',
      name: 'Название магазина',
    },
    url: Astro.url.href,
  },
  aggregateRating: product.data.rating
    ? {
        '@type': 'AggregateRating',
        ratingValue: product.data.rating.value,
        reviewCount: product.data.rating.count,
        bestRating: 5,
        worstRating: 1,
      }
    : undefined,
};
---

Звёздочки рейтинга в выдаче Google — прямой рост CTR на 15-25%.

Схема: Organization (главная страница)

code
---
// src/pages/index.astro или src/layouts/BaseLayout.astro
const orgSchema = {
  '@context': 'https://schema.org',
  '@type': 'Organization',
  name: 'Название компании',
  url: Astro.site?.href,
  logo: {
    '@type': 'ImageObject',
    url: new URL('/logo.png', Astro.site).href,
    width: 200,
    height: 60,
  },
  contactPoint: {
    '@type': 'ContactPoint',
    telephone: '+7-XXX-XXX-XX-XX',
    contactType: 'customer service',
    availableLanguage: 'Russian',
  },
  address: {
    '@type': 'PostalAddress',
    addressLocality: 'Москва',
    addressCountry: 'RU',
  },
  sameAs: [
    'https://vk.com/yourpage',
    'https://t.me/yourchannel',
    'https://github.com/yourorg',
  ],
};
---

Схема: WebSite + SearchAction

Добавьте sitelinks searchbox (поисковая строка прямо в выдаче):

code
---
const websiteSchema = {
  '@context': 'https://schema.org',
  '@type': 'WebSite',
  name: 'Название сайта',
  url: Astro.site?.href,
  potentialAction: {
    '@type': 'SearchAction',
    target: {
      '@type': 'EntryPoint',
      urlTemplate: `${Astro.site}search?q={search_term_string}`,
    },
    'query-input': 'required name=search_term_string',
  },
};
---

Схема: Person (портфолио / автор)

code
---
const personSchema = {
  '@context': 'https://schema.org',
  '@type': 'Person',
  name: 'Имя Фамилия',
  jobTitle: 'Frontend Developer',
  url: Astro.site?.href,
  image: new URL('/photo.jpg', Astro.site).href,
  email: 'hello@example.com',
  sameAs: [
    'https://github.com/username',
    'https://linkedin.com/in/username',
    'https://t.me/username',
  ],
  knowsAbout: ['Astro', 'React', 'TypeScript', 'Web Performance'],
  alumniOf: {
    '@type': 'CollegeOrUniversity',
    name: 'Название университета',
  },
};
---

Многосхемный компонент

Для удобства объедините несколько схем в одном блоке:

code
---
// src/components/ArticleSchemas.astro
// Объединяет Article + BreadcrumbList + Author Person
---

<script
  type="application/ld+json"
  set:html={JSON.stringify([articleSchema, breadcrumbSchema, authorSchema])}
/>

Google поддерживает массив схем в одном теге <script>.

Проверка разметки

1. Rich Results Test (официальный инструмент Google):

code
https://search.google.com/test/rich-results

Показывает, какие rich results доступны для страницы.

2. Schema Markup Validator:

code
https://validator.schema.org/

Проверяет валидность структуры схемы.

3. В коде: проверить при сборке

code
// src/lib/validateSchema.ts (для CI)
import Ajv from 'ajv';

export function validateArticleSchema(schema: unknown) {
  // Базовая проверка обязательных полей
  const s = schema as Record<string, unknown>;
  const required = ['@context', '@type', 'headline', 'datePublished', 'author'];
  const missing = required.filter((f) => !s[f]);
  if (missing.length) {
    console.warn('Missing schema fields:', missing);
  }
}

Распространённые ошибки

ОшибкаПоследствиеРешение
Нет @contextСхема не распознаётсяВсегда добавлять 'https://schema.org'
URL не абсолютныйПредупреждение в валидатореИспользовать new URL(path, Astro.site)
datePublished без ISO 8601Дата не распознаётсяdate.toISOString()
Схема в комментарии или без type=“application/ld+json”ИгнорируетсяПроверить атрибуты тега
Дублирование схем одного типаКонфликтОдна схема каждого типа на страницу

Итог

JSON-LD structured data — самый эффективный SEO-инструмент с точки зрения соотношения усилий и результата. В Astro добавление занимает час: создайте компонент JsonLd.astro и используйте нужные схемы на каждом типе страниц. Практический результат — rich snippets в Google, рост CTR на 15-30% и лучшее понимание контента поисковыми ботами. Начните с Article, BreadcrumbList и Organization — это покрывает 80% потребностей контентного сайта.

Портрет автора Дмитрий Соколов

Senior Frontend Engineer / Tech Writer

Senior Frontend Engineer с 9-летним опытом. Специализируется на Astro.js и JAMstack.

Комментарии

Загрузка комментариев...

Оставить комментарий

Комментарии проходят модерацию перед публикацией. Правила

Рекомендуем к прочтению