Structured data can remain valid JSON while naming a property that does not belong to its declared schema.org type. A repeatable URL check catches those vocabulary mismatches and missing markup before a page change reaches search crawlers.

The validator below fits an existing Node.js project and reads JSON-LD, Microdata, and RDFa from the HTML returned by the web server. It downloads the current schema.org vocabulary on each run, so the check is not tied to a bundled vocabulary snapshot.

Server-rendered markup is the boundary for this method because the page fetch does not execute browser JavaScript. Use the Schema Markup Validator for JavaScript-injected entities and the Rich Results Test when the final decision is eligibility for a Google search feature; valid vocabulary alone does not guarantee a rich result.

Steps to validate structured data for a website:

  1. Install the structured-data validator and HTML extractor under devDependencies in the existing Node.js project's package.json.
    $ npm install --save-dev @adobe/structured-data-validator @marbec/web-auto-extractor
  2. Create check-schema.mjs with the page-fetch and structured-data extraction section.
    check-schema.mjs
    import Validator from '@adobe/structured-data-validator';
    import WebAutoExtractor from '@marbec/web-auto-extractor';
     
    if (!process.argv[2]) {
      console.error('Usage: node check-schema.mjs <url>');
      process.exit(2);
    }
     
    const targetUrl = new URL(process.argv[2]);
    const response = await fetch(targetUrl);
     
    if (!response.ok) {
      throw new Error(`Page request failed: ${response.status} ${response.statusText}`);
    }
     
    const html = await response.text();
    const extractedData = new WebAutoExtractor({
      addLocation: true,
      embedSource: ['rdfa', 'microdata'],
    }).parse(html);
     
    const itemTypes = ['jsonld', 'microdata', 'rdfa'].flatMap((format) =>
      Object.entries(extractedData[format]).flatMap(([type, items]) =>
        items.map(() => type),
      ),
    );
     
    if (itemTypes.length === 0) {
      console.error('No structured data found.');
      process.exit(1);
    }
  3. Append the current Schema.org vocabulary and issue-reporting section to check-schema.mjs.
    check-schema.mjs
    const vocabularyResponse = await fetch(
      'https://schema.org/version/latest/schemaorg-all-https.jsonld',
    );
     
    if (!vocabularyResponse.ok) {
      throw new Error(`Schema.org request failed: ${vocabularyResponse.status}`);
    }
     
    const vocabulary = await vocabularyResponse.json();
    const issues = await new Validator(vocabulary).validate(extractedData);
     
    if (issues.length === 0) {
      const typeList = [...new Set(itemTypes)].join(', ');
      console.log(`Valid: ${itemTypes.length} item(s) (${typeList}).`);
      process.exit(0);
    }
     
    for (const issue of issues) {
      console.log(`${issue.severity}: ${issue.issueMessage}`);
    }
     
    process.exit(1);
  4. Run check-schema.mjs against the public canonical page URL, using https://schema.org/ as the verified example.
    $ node check-schema.mjs https://schema.org/
    Valid: 1 item(s) (WebSite).

    A missing entity, unsupported property, request failure, or vocabulary issue returns a nonzero exit status so the same command can gate a build or deployment.

Share this guide