The instinct is to check the pages that matter. That is also why the same broken og:image survives for a year: nobody checks the 400 blog posts generated by the same template. Bulk auditing inverts the order — find the template bug first, then fix it once.
Start from the sitemap, not the homepage
Your sitemap is already the list of URLs you claim are important. Export it, deduplicate, and run the batch against that set rather than crawling links blindly. It gives you a bounded scope and a score you can compare week over week.
# Pull URLs out of the sitemap
curl -s https://example.com/sitemap.xml \
| grep -o '<loc>[^<]*</loc>' \
| sed 's#</\?loc>##g' \
> urls.txt
wc -l urls.txt Group by template, not by URL
Add a column for the template or route pattern — /blog/:slug, /products/:id, /docs/:section. Group the results by that column. You are looking for a group where every member fails the same check, which points at one file rather than 300 content entries.
- Every /blog/:slug page missing og:image: one layout file to fix.
- Every /products/:id page using the category image: one product template.
- Random failures across all groups: an asset hosting or CDN problem, not a template problem.
Three tiers of severity
- 01 Blocking: no og:image, a relative URL, or an image under 200 × 200. The card renders without an image everywhere.
- 02 Degrading: title or description over the truncation limit, or og:url not matching the canonical. The card renders but reads badly.
- 03 Cosmetic: missing og:image:alt, an unused twitter:card, or a suboptimal type. The card works and could be better.
Patterns only a batch reveals
- One shared og:image across 200 pages, because the CMS falls back to a default instead of the featured image.
- Canonical and og:url pointing at different hosts — www versus non-www — which splits previews between two cache entries.
- A staging hostname leaking into production tags after a deploy.
- Images that are all exactly 1200 × 628, suggesting a generator that ignores the 630 requirement.
- Every page on the site sharing the same og:title: the template variable never resolved.
Run it in the pipeline, not in a spreadsheet
The audit is only useful if it repeats. Wire it into the build or a scheduled job and fail on blocking issues only — a build that fails on cosmetic warnings gets disabled within a week.
# Batch audit against the sitemap, then fail the job on blocking issues
curl -s -X POST https://siteassets.dev/api/v1/audit/batch \
-H "Authorization: Bearer $SITEASSETS_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"urls\": $(cat urls.json)}" \
-o audit.json
jq '.results[] | select(.issues[]?.severity == "error")' audit.json Fix in this order
- 01 The template that covers the most URLs.
- 02 The blocking issues inside that template.
- 03 The canonical and host consistency across the whole site.
- 04 Truncation limits and alt text, once the cards render at all.
A single pass over a few hundred URLs usually collapses into two or three template fixes. That is the entire point: the work is small once the pattern is visible.