b2KIT

Course Schema Builder

Build Course schema markup with provider, description, cost, and schedule. Generate JSON-LD for education rich results.

Tested tool guide Tested browser tools Checked August 16, 2026

What Course Schema Builder does, with a checked example

The markup Google reads about a course is separate from the page a human reads. Enter the enrollment facts - course title, description, provider name and URL, price and currency, mode, start and end dates - and the tool assembles them into a JSON-LD object following schema.org's Course and CourseInstance types, with the provider nested as an Organization and the cost nested as an Offer. The surprise most users hit: Google's Course rich result only qualifies for courses with clear enrollment information, so name and description alone do not qualify; the markup needs a price, a location, or a start date.

Worked example

A concrete input and expected output from the current implementation.

Input

Course name: Intro to Python Programming
Description: A four-week online course covering Python fundamentals.
Provider: Northwind Academy, https://northwind.example.com
Price: 49.00 USD (Paid)
Course mode: online
Start date: 2026-09-01
End date: 2026-09-28

Expected output

{
  "@context": "https://schema.org",
  "@type": "Course",
  "name": "Intro to Python Programming",
  "description": "A four-week online course covering Python fundamentals.",
  "provider": {
    "@type": "Organization",
    "name": "Northwind Academy",
    "sameAs": "https://northwind.example.com"
  },
  "hasCourseInstance": {
    "@type": "CourseInstance",
    "courseMode": "online",
    "startDate": "2026-09-01",
    "endDate": "2026-09-28",
    "offers": {
      "@type": "Offer",
      "category": "Paid",
      "price": "49.00",
      "priceCurrency": "USD"
    }
  }
}

Each entered value lands where schema.org expects it: the provider becomes a nested Organization, and mode, dates, and cost sit on a nested CourseInstance with an Offer, which is the structure Google's Course rich result reads. The output contains nothing beyond the entered values reorganized into that nesting.

How the result is produced

1

Field mapping

Every input maps to a schema.org property: name, description, and provider sit on Course itself; courseMode, startDate, and endDate belong to a nested CourseInstance; price, priceCurrency, and category belong to a nested Offer. The tool emits the finished object as JSON-LD, which you paste into a <script type="application/ld+json"> element in the page head.

2

Eligibility signals

Google's Course rich result demands more than a title: the markup must carry enrollment information. The tool keeps track of the three accepted signals - an offer with price and currency, a location, or a start date - and flags the output when none of them is present, since such a record cannot qualify no matter how well formed it is.

Good uses

  • Adding Course markup to a course landing page so Google can show an education rich result with provider name, price, and dates.
  • Rebuilding hand-written JSON-LD in a CMS template where the nesting of Course, CourseInstance, and Offer has drifted out of schema.org shape.
  • Producing a reference copy of the markup for a QA pass, to compare against what the live page actually displays.

Limits and checks

  • Eligible markup is not the same as a rich result. Google must crawl the page, decide the enhancement is useful, and keep showing it; days or weeks can pass, and a page that qualifies today can stop qualifying after its content changes.
  • The price and dates in the markup must match the visible page, and dates must be ISO 8601 (YYYY-MM-DD). Contradictory structured data can be treated as misleading, and dates in other formats are not reliably read by consumers.
  • The output is a snippet, not a placement guarantee. It belongs on the page about that single course; placing Course markup on a category page or index page describes the wrong content to Google.

Common questions

Do I need one of these on every course page?

Yes, if you want rich results for each course. Google reads the markup on each course's own page, so a template that emits the same name and price on every course is wrong for all but one of them. Generate per-course values, then test a sample with Google's Rich Results Test before treating the markup as live.

My course is free. Do I still need an offers block?

Not necessarily. A start date or a physical location satisfies the enrollment requirement on its own, so a free in-person course can use its venue. For an online free course, the standard pattern is an offer with price 0, a currency, and category Free, which keeps the markup eligible and unambiguous.

References and verification

The example and behavioral notes were checked against the browser implementation. Standards and primary references below define the relevant format, formula, or platform behavior.

Related Tools