Skip to main content
XMLDir

Search 106 pages — formats, namespaces, parser messages, schema errors and tools.

Integrations

Fail the build, not the customer

A malformed sitemap is a deploy problem that behaves like an SEO problem three weeks later. These are the ways to move that discovery back to the pull request.

GitHub code scanning

The API speaks SARIF 2.1.0, which is the format GitHub code scanning ingests directly. That single fact is what makes this worth wiring up: the output is not a log line, it is an annotation on the exact line of the exact file, on the pull request that introduced it.

.github/workflows/validate-xml.yml
name: Validate XML

on:
  pull_request:
    paths:
      - "public/sitemap.xml"
      - "**/*.xml"

permissions:
  contents: read
  security-events: write   # required to upload SARIF

jobs:
  xml:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Validate sitemap
        run: |
          curl -sS --fail-with-body \
            -X POST "https://xmldir.com/api/v1/validate?format=sarif" \
            -H "Authorization: Bearer ${{ secrets.XMLDIR_API_KEY }}" \
            -H "Content-Type: application/xml" \
            --data-binary @public/sitemap.xml \
            > xmldir.sarif

      # Runs even when validation failed, so the annotations still appear.
      - name: Upload results
        if: always()
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: xmldir.sarif
          category: xmldir

Two things that catch people out

security-events: write is required to upload SARIF, and the default token does not have it. And the upload step needs if: always() — without it, a failed validation skips the upload and you get a red build with no annotations explaining why.

A clean run is not an empty file

Valid documents return a well-formed SARIF log with an empty results array. Code scanning needs that to clear previously reported findings — an empty file would leave stale annotations on the pull request forever.

What gets reported

4 rules, each with a stable id so a finding can be suppressed or tracked over time.

  • xml/well-formed

    WellFormed

    Document must be well-formed XML

  • xml/schema-valid

    SchemaValid

    Document must satisfy the supplied XSD

  • xml/namespace-undeclared

    NamespaceUndeclared

    Namespace prefixes must be declared before use

  • xml/namespace-unused

    NamespaceUnused

    Declared namespaces should be used

Full request and response shapes are in the API reference

Webhooks for monitored sources

CI catches the XML you generate. Monitoring catches the XML you do not control — a partner feed, a supplier's endpoint. Register a URL, enable monitoring, and a POST arrives when its structure changes, with the paths that moved.

The payload carries the change, not the document. Routing a partner's XML through a chat integration is how payloads end up somewhere they should not be.

POST to your endpoint
{
  "source": "https://example.com/sitemap.xml",
  "detectedKind": "sitemap",
  "checkedAt": "2026-08-18T09:14:22Z",
  "changed": true,
  "changeCount": 3,
  "added": ["/urlset/url/video:video"],
  "removed": [],
  "changedPaths": ["/urlset/url/lastmod"]
}

Anything that speaks HTTP

Any CI

GitLab, Jenkins, CircleCI, Buildkite — it is one curl and a non-zero exit code. SARIF is the bonus, not the requirement.

Alerting

Point a monitoring webhook at whatever already pages you. The payload is small and stable enough to route on.

Pre-commit

The same endpoint works from a git hook, which catches a malformed document before it is ever pushed.

Get started

Get an API key and put this in your pipeline.

Keys are free, issued per account, and stored only as a hash — so a key is shown once and cannot be recovered by anyone, including us.