Last updated: March 22, 2026

Overview

When a monitored URL’s schema changes between scans, ValidGraph generates a detailed diff showing exactly what was added, removed, or modified. This makes it easy to identify regressions caused by deployments, CMS updates, or content changes.

How It Works

1. Each re-scan result is compared to the previous scan
2. A diff is generated showing:
– Added schema types or properties
– Removed schema types or properties
– Modified property values
– Score changes (improvement or regression)
3. Changes are categorized by severity
4. Notifications are sent for significant changes

Tier Availability

| Tier | Available |
|——|———–|
| Free | No |
| Pro | No |
| Agency | Yes |
| Enterprise | Yes |

URL Monitoring: Configure which URLs to track
Automated Re-scans: Triggers the comparison
Email Alerts: Notifications for detected changes

Quick Start: Detect Schema Changes Between Scans

Step 1: Set up monitoring on a URL (see URL Monitoring)

Step 2: After a rescan, the diff is automatically generated

Step 3: View the diff in dashboard — See exactly what changed (added, removed, modified properties)

Step 4: Review severity — High (required properties changed), medium (recommended properties), low (optional)

Example scenario:
You deploy a site update. Previous scan showed Article with headline, author, datePublished. New scan shows those are gone and replaced with BlogPosting type. Change severity: HIGH (schema type changed). Alert fires immediately.

Technical Details

Schema Diff Endpoint

Query schema differences between two validations:

GET /wp-json/validgraph/v1/schema-diff?url=https://example.com/article&validation_id_a=val_old_001&validation_id_b=val_new_002

Response:

{
  "success": true,
  "data": {
    "url": "https://example.com/article",
    "validation_a": {
      "validation_id": "val_old_001",
      "timestamp": "2024-03-14T06:00:00Z",
      "types": ["Article"],
      "schema_summary": {
        "Article": {
          "headline": "Example Article",
          "author": {"@type": "Person", "name": "John Doe"},
          "datePublished": "2024-03-14"
        }
      }
    },
    "validation_b": {
      "validation_id": "val_new_002",
      "timestamp": "2024-03-21T06:00:00Z",
      "types": ["BlogPosting"],
      "schema_summary": {
        "BlogPosting": {
          "headline": "Example Article",
          "author": {"@type": "Person", "name": "John Doe"},
          "datePublished": "2024-03-21"
        }
      }
    },
    "has_changes": true,
    "change_summary": {
      "types_changed": {
        "removed": ["Article"],
        "added": ["BlogPosting"],
        "severity": "high"
      },
      "property_changes": {
        "Article": {
          "removed": [
            {"property": "datePublished", "value": "2024-03-14", "severity": "high"}
          ],
          "added": [],
          "modified": []
        }
      }
    },
    "detailed_diff": {
      "added": [
        {
          "type": "BlogPosting",
          "property": "datePublished",
          "old_value": null,
          "new_value": "2024-03-21",
          "value_type": "Date",
          "severity": "high"
        }
      ],
      "removed": [
        {
          "type": "Article",
          "property": "datePublished",
          "old_value": "2024-03-14",
          "new_value": null,
          "value_type": "Date",
          "severity": "high"
        }
      ],
      "modified": [
        {
          "type": "BlogPosting",
          "property": "headline",
          "old_value": "Example Article",
          "new_value": "Example Article (Updated)",
          "severity": "low"
        }
      ]
    },
    "overall_severity": "high",
    "has_blocking_changes": true,
    "recommendation": "Schema type changed from Article to BlogPosting. This may impact rich snippet eligibility."
  }
}

Schema Changes List Endpoint

Get all recent schema changes for monitored URLs:

GET /wp-json/validgraph/v1/schema-changes

Response:

{
  "success": true,
  "data": {
    "recent_changes": [
      {
        "monitoring_id": "mon_abc123",
        "url": "https://example.com/article",
        "timestamp": "2024-03-21T06:15:00Z",
        "has_changes": true,
        "change_severity": "high",
        "change_summary": "Schema type changed: Article → BlogPosting",
        "validation_pair": {
          "previous": "val_old_001",
          "current": "val_new_002"
        }
      },
      {
        "monitoring_id": "mon_def456",
        "url": "https://example.com/product",
        "timestamp": "2024-03-21T06:10:00Z",
        "has_changes": true,
        "change_severity": "medium",
        "change_summary": "Property removed: image; Property modified: price (999 → 899)",
        "validation_pair": {
          "previous": "val_scan_005",
          "current": "val_scan_006"
        }
      }
    ],
    "total_changed": 2,
    "total_monitored": 25,
    "change_rate": "8%"
  }
}

Severity Levels

Severity is determined by the weight of changed properties:

| Severity | Criteria | Examples |
|———-|———-|———-|
| High | Required properties changed | Type changed, required property removed |
| Medium | Recommended properties changed | image removed, description modified |
| Low | Optional properties changed | keywords removed, minor text changes |

Diff Categories

Added:
– New schema types detected
– New properties not in previous scan
– New nested objects

Removed:
– Schema types no longer present
– Properties deleted from markup
– Nested objects deleted

Modified:
– Property values changed
– Types changed (e.g., String → Number)
– Nested object structure changes

Detailed Change Example

Recipe schema property change example:

{
  "detailed_diff": {
    "modified": [
      {
        "type": "Recipe",
        "property": "prepTime",
        "old_value": "PT15M",
        "new_value": "PT20M",
        "value_type": "Duration",
        "severity": "low",
        "impact": "Prep time increased by 5 minutes"
      },
      {
        "type": "Recipe",
        "property": "aggregateRating",
        "old_value": {
          "ratingValue": 4.5,
          "ratingCount": 120
        },
        "new_value": {
          "ratingValue": 4.3,
          "ratingCount": 135
        },
        "nested_changes": {
          "ratingValue": {
            "old": 4.5,
            "new": 4.3,
            "change": -0.2
          },
          "ratingCount": {
            "old": 120,
            "new": 135,
            "change": 15
          }
        },
        "severity": "low",
        "impact": "Rating slightly decreased but vote count increased"
      }
    ]
  }
}

Alert Triggers for Schema Changes

The schema diff automatically triggers alerts when:

1. High-severity changes detected: Type changes, required properties removed
2. New validation errors: Markup became invalid
3. Score regression: Score dropped below threshold (configurable per URL)
4. Rich snippet eligibility loss: Markup no longer meets Google requirements

Example alert payload:

{
  "alert_id": "alert_change_789",
  "monitoring_id": "mon_abc123",
  "url": "https://example.com/article",
  "alert_type": "schema_change_high_severity",
  "triggered_at": "2024-03-21T06:15:00Z",
  "change_summary": "Schema type changed: Article → BlogPosting",
  "severity": "high",
  "action_recommended": "Review new markup; verify it meets rich snippet requirements for BlogPosting type",
  "notification_channels": ["email", "webhook"]
}

References

JSON Diff Standards: https://tools.ietf.org/html/rfc6902 (JSON Patch)
JSON Merge Patch: https://tools.ietf.org/html/rfc7386
Schema.org Type Hierarchy: https://schema.org/docs/documents.html
Semantic Versioning: https://semver.org/ (for change severity)
Change Detection Patterns: https://en.wikipedia.org/wiki/Diff