# How to add JSON-LD structured data to your website - agentmarkup

> Inject schema.org JSON-LD structured data into your Vite, Astro, or Next.js website at build time. Use type-safe presets for WebSite, Organization, Article, FAQ, Product, and Offer schemas.

Source: https://agentmarkup.dev/docs/json-ld/

# How to add JSON-LD structured data to your website

JSON-LD (JavaScript Object Notation for Linked Data) is the format Google, Bing, and other search engines use to understand your page content. agentmarkup injects schema.org JSON-LD into your HTML pages at build time for Vite, Astro, and Next.js with XSS-safe serialization and type-safe presets.

## What is JSON-LD structured data?

Structured data tells search engines exactly what your page is about. Instead of guessing from HTML content, search engines read your JSON-LD and understand that a page is a Product with a price, an Article with a publish date, or an Organization with a logo.

This powers rich results in Google Search, including star ratings, FAQ dropdowns, product cards, and knowledge panels. Without structured data, search engines can only guess at your page content.

## Built-in schema.org presets

agentmarkup includes 6 type-safe presets for common structured data types. Each preset validates required fields at build time and generates spec-compliant JSON-LD.

 Preset Schema type Use case webSite WebSite Site-level schema with optional search action organization Organization Company or brand identity article Article Blog posts, news, content pages faqPage FAQPage Question and answer pages product Product E-commerce product pages offer Offer Pricing and availability

## Using presets

Apply schemas globally (every page) or per-page. Global schemas like `webSite` and `organization` go in `globalSchemas`. Page-specific schemas go in `pages`. The schema config is adapter-agnostic, so the same object works with `@agentmarkup/vite`, `@agentmarkup/astro`, and `@agentmarkup/next`.

```
const agentmarkupConfig = {
 site: 'https://myshop.com',
 name: 'My Shop',
 globalSchemas: [
 { preset: 'webSite', name: 'My Shop', url: 'https://myshop.com' },
 { preset: 'organization', name: 'My Shop', url: 'https://myshop.com', logo: '/logo.png' },
 ],
 pages: [
 {
 path: '/faq',
 schemas: [{
 preset: 'faqPage',
 url: 'https://myshop.com/faq',
 questions: [
 { question: 'Do you ship internationally?', answer: 'Yes, to 50+ countries.' },
 ],
 }],
 },
 ],
}
```

## Framework wrappers

After defining the shared schema config, pass it into the adapter for the framework that owns your final output:

```
// Vite
import { defineConfig } from 'vite'
import { agentmarkup } from '@agentmarkup/vite'

export default defineConfig({
 plugins: [agentmarkup(agentmarkupConfig)],
})

// Astro
import { defineConfig } from 'astro/config'
import { agentmarkup } from '@agentmarkup/astro'

export default defineConfig({
 integrations: [agentmarkup(agentmarkupConfig)],
})

// Next.js
import type { NextConfig } from 'next'
import { withAgentmarkup } from '@agentmarkup/next'

const nextConfig: NextConfig = {
 output: 'export',
}

export default withAgentmarkup(agentmarkupConfig, nextConfig)
```

## Custom schemas

You can use any schema.org type by passing an object with an `@type` field. agentmarkup automatically adds the `@context` and handles serialization.

```
pages: [
 {
 path: '/products/wallets',
 schemas: [{
 '@type': 'Product',
 name: 'Classic Leather Wallet',
 description: 'Full-grain leather bifold wallet.',
 image: 'https://myshop.com/images/wallet.jpg',
 sku: 'WALLET-001',
 offers: {
 '@type': 'Offer',
 price: '89',
 priceCurrency: 'USD',
 availability: 'https://schema.org/InStock',
 },
 }],
 },
]
```

## XSS-safe output

agentmarkup escapes dangerous characters (`<`, `>`, `&`, `'`) to unicode escapes before injecting JSON-LD into HTML. This prevents XSS attacks through structured data injection.

```
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"WebSite","name":"My Shop","url":"https://myshop.com"}
</script>
```

## Build-time validation

Every schema is validated during build. Missing required fields produce errors. Missing recommended fields produce warnings. You see exactly what needs fixing in your terminal before deploying.

- **Required field errors:** Product without `name`, Article without `headline`
- **Recommended field warnings:** Organization without `logo`, Product without `sku`
- **Custom schema checks:** Every custom schema must have an `@type` field

Combined with [llms.txt generation](/docs/llms-txt/), [markdown mirrors](/blog/markdown-mirrors/), and [AI crawler management](/docs/ai-crawlers/), this gives your website a fuller machine-readable surface instead of relying on structured data alone.

## Frequently asked questions

 Do I need JSON-LD if I already have meta tags?

Yes. Meta tags (title, description) help search engines understand a single page. JSON-LD tells them what kind of thing the page represents (a product, an article, an FAQ) with structured fields they can use for rich results.

 Can I add multiple schemas to one page?

Yes. Use the `pages` config to add multiple schemas per path. Each schema generates its own `<script type="application/ld+json">` tag. Global schemas are also added to every page.

 What if I need a schema type that is not a preset?

Pass any object with an `@type` field. agentmarkup will add `@context` automatically and serialize it safely. Presets just save you from remembering required fields.
