GuardLabs
demo / framer-jsonld
Framer · code component

JSON-LD разметка для Framer, которой у платформы нет из коробки

Framer рендерит быстрые и красивые сайты, но structured data для поисковиков не отдаёт: ни Product, ни FAQPage, ни LocalBusiness. Для магазина или сервиса это потерянные rich-сниппеты в выдаче. Ниже code component, который закрывает дыру, и живая проверка прямо на этой странице.

Боль

Что теряет сайт на Framer без schema.org

Симптомы

  • Товар в выдаче без цены, рейтинга и наличия: сосед с разметкой выглядит богаче.
  • FAQ не раскрывается прямо в поиске, хотя контент на странице есть.
  • SEO-аудит клиента стабильно краснеет на пункте structured data.

Почему так

  • Нативного поля «JSON-LD» в настройках страницы Framer нет.
  • Вставка в head решает только статичные случаи: данные из CMS туда руками не подтянешь.
  • Штатный путь платформы: code component на React, который сам собирает разметку из props и кладёт её в документ.

Живой артефакт

Эта страница уже размечена

Инжектор, идентичный по логике code component ниже, при загрузке добавил в документ два блока JSON-LD: Product и FAQPage. Кнопка запускает встроенный чекер: он читает документ и проверяет обязательные поля так же, как это делает валидатор Google.

Решение

Code component с настройками в панели Framer

Компонент кладётся на канвас, все поля редактируются в правой панели через addPropertyControls: маркетолог меняет цену и валюту без разработчика. На опубликованном сайте компонент невидим, в документ попадает только script с разметкой.

import { addPropertyControls, ControlType } from "framer"
import { useEffect } from "react"

export default function SchemaProduct(props) {
    useEffect(() => {
        const data = {
            "@context": "https://schema.org",
            "@type": "Product",
            name: props.name,
            description: props.description,
            offers: {
                "@type": "Offer",
                price: String(props.price),
                priceCurrency: props.currency,
                availability: props.inStock
                    ? "https://schema.org/InStock"
                    : "https://schema.org/OutOfStock",
            },
        }
        const tag = document.createElement("script")
        tag.type = "application/ld+json"
        tag.textContent = JSON.stringify(data)
        document.head.appendChild(tag)
        return () => tag.remove()
    }, [props])
    return null
}

addPropertyControls(SchemaProduct, {
    name: { type: ControlType.String, title: "Товар" },
    description: { type: ControlType.String, title: "Описание" },
    price: { type: ControlType.Number, title: "Цена" },
    currency: { type: ControlType.String, title: "Валюта", defaultValue: "UAH" },
    inStock: { type: ControlType.Boolean, title: "В наличии", defaultValue: true },
})

Важная деталь: cleanup в useEffect возвращает функцию удаления тега. Частая ошибка в чужих Framer-проектах, когда из useEffect возвращают что-то другое, даёт «We detected a problem in one of your code components». Для FAQPage компонент отличается только сборкой объекта data из списка вопросов.

Как проверить

Проверка за две минуты

  1. Нажмите кнопку выше: чекер найдёт два блока JSON-LD и покажет статус обязательных полей.
  2. Откройте view-source и найдите application/ld+json: разметка реально в документе, а не нарисована интерфейсом.
  3. Прогоните адрес этой страницы через Google Rich Results Test: типы Product и FAQPage распознаются.
  4. В реальном проекте Framer поля компонента редактируются в правой панели, без правок кода.