How to batch-purge unused svg definitions with the jad desktop runner
- Step 1Understand the execution model first — The purger requires a DOM (
DOMParser/XMLSerializer). It is not in the server-safe set, so there is no cloud REST endpoint. Your two real options are: drive the desktop runner (headless browser, Pro-tier) per file, or script the in-browser web tool. Plan your pipeline around one of those. - Step 2Install and pair the JAD desktop runner on a Pro plan — The runner exposes
svg-unused-defs-purgeras arunner-builtinoperation requiring the Pro tier. When the runner is reachable and the user is Pro+, the web client auto-routes jobs to it; otherwise it falls back to the browser tab. Confirm the runner reports the headless capability for DOM-based SVG tools. - Step 3Process one SVG per job — Each job takes a single SVG file plus an empty options object (
{}— the tool ignores options). Loop over your folder and dispatch one job per file. There is no multi-file batch array for this tool; batching is your loop, not a server feature. - Step 4Capture the per-file metrics — Each result reports
Defs removed, original size, and output size. Log these per file so you can see which icons carried the most dead weight and prove the cleanup in CI output. - Step 5Add a visual regression gate — Because external-CSS and JS-referenced ids can be removed as false positives, run your icon visual-regression suite (Storybook + Chromatic, Percy, or screenshot diffing) after purging. A pixel diff catches any def that was actually in use via a path the scan can't see.
- Step 6Re-run for transitive orphans, then minify — Run the purger a second time over the output to collect defs that only became dead after the first pass (def-to-def chains). Then pass results through the Pro-Minifier for byte-level shrinkage.
Execution paths for automated defs purging
The purger needs a DOM. These are the real ways to automate it — note that a stateless REST API is not one of them.
| Path | Available? | How it works | Notes |
|---|---|---|---|
| Cloud REST endpoint | No | Engine throws: "not exposed via the API — requires browser-side processing" | The slug is absent from the server-safe set |
| JAD desktop runner | Yes (Pro) | runner-builtin op in the runner's headless browser; web client auto-routes Pro jobs to it | Local execution; nothing uploaded; falls back to browser on any runner error |
| Browser web tool | Yes (Pro) | Single file per run via drop/paste; DOMParser in the tab | One SVG at a time; loop manually for many files |
| SVGO plugin equivalent | Third-party | cleanupIds/custom plugins approximate the behaviour in Node | Different reference-detection rules than this tool |
Per-job inputs and outputs
What a single purge job consumes and produces. Identical for every file — there is nothing to configure.
| Field | Value |
|---|---|
| Input | One .svg file (or pasted SVG source) |
| Options | {} — the tool defines no options and ignores any passed |
| Tier required | Pro (per-file limit 50 MB) |
| Output file | <stem>-purged.svg |
| Metric | Defs removed: N, plus original/output byte sizes |
| Removal rule | Id-bearing defs > * not matched by url(#id) or (xlink:)?href="#id" anywhere in the doc |
Cookbook
Automation recipes that respect the real execution model — no fictional batch API, no preserve-id flag.
Loop the desktop runner over an icons folder
Drive the runner one file at a time. The loop is your batch; each job carries a single file and an empty options object.
# pseudo-driver against the local JAD runner
for f in ./src/icons/*.svg; do
jad-runner run svg-unused-defs-purger \
--file "$f" \
--out "./dist/icons/$(basename "${f%.svg}")-purged.svg"
done
# Each run prints: Defs removed: N (original → output bytes)
# No --preserve / --options flags exist for this tool.Two-pass purge to clear transitive orphans
A second pass collects defs that only became dead after the first removed their sole referrer (the def-to-def cascade).
purge ./icon.svg → icon-purged.svg (Defs removed: 2) purge ./icon-purged.svg → icon-purged-purged.svg (Defs removed: 1) # Pass 1 removed a clipPath; the gradient it referenced # became orphaned and is swept up only on pass 2.
Purge → minify → tune precision pipeline
Chain three SVG tools so each does its one job. Purge first so the minifier has less markup to process.
stage 1 svg-unused-defs-purger (drop dead <defs>) stage 2 svg-pro-minifier (strip comments/whitespace) stage 3 svg-precision-tuner (round coords to 2 dp) # Order matters: removing defs before minifying means the # minifier never touches markup that's about to be deleted.
Pre-commit guard on staged SVGs
Run the purger only on SVGs staged for commit so dead defs never enter history. Drive the runner per staged file.
# .git/hooks/pre-commit (sketch) files=$(git diff --cached --name-only --diff-filter=ACM | grep '\.svg$') for f in $files; do jad-runner run svg-unused-defs-purger --file "$f" --inplace git add "$f" done # Commit proceeds with purged SVGs.
Gate the pipeline on a visual diff
Because external-CSS / JS-referenced ids can be false-positived away, fail the build if any icon changes pixels after purging.
purge all icons → render each to PNG → diff vs baseline
if any diff > 0 px:
FAIL — a 'dead' def was actually referenced
(likely from external CSS or JS).
→ exclude that file from the purge set, or inline the ref.
else:
PASS — defs removal was safe.Edge cases and what actually happens
Calling a REST API for this tool
Not exposedThere is no cloud endpoint. The engine throws "svg-unused-defs-purger is not exposed via the API — it requires browser-side processing (DOM, Canvas, or remote-font fetch). Use the web tool." Automate via the desktop runner or the browser tool instead.
Passing a preserve-ids parameter in the job options
IgnoredThe tool defines no options. Any preserve_ids, purge_unused_defs, or similar field in the options object is ignored — removal is fully automatic. To protect a def with no static reference, keep that file out of the purge set.
Sending a multi-file batch array in one call
Unsupported (rejected)This is a single-file operation. There is no server-side batch array — you loop and dispatch one job per file. Only the sprite builder is multi-file among the SVG tools.
Free-tier automation attempt
Pro requiredThe purger requires Pro both in the browser (upgrade overlay otherwise) and in the runner (tierRequired: pro). Free-tier jobs are not dispatched to the runner at all — runner acceleration is a paid perk — so they would also fail the browser gate. Use a Pro plan.
Icon referenced only from a Vue/React component's CSS
Removed in errorIf a component stylesheet applies filter: url(#fx) from outside the SVG, the purger removes fx as unused. The visual-regression gate is your safety net — diff the rendered icon and exclude any file that changes.
Runner unreachable mid-batch
Falls backIf the runner errors, the web client logs a warning and falls back to the in-browser path so the user still gets a result. In a headless driver, handle the fallback explicitly: if the runner call fails, process that file in the browser tool or retry.
A file with embedded base64 raster blows the size limit
413 rejectedSVGs that embed PNG/JPEG as base64 can exceed the 50 MB Pro ceiling and are rejected before processing. The purger does not touch raster payloads anyway — strip or externalise the embedded image first; estimate the weight with the SVG Compression Estimator.
Expecting transitive cleanup in one pass
By designA single pass keeps defs referenced only inside a doomed def. Pipelines that want a fully minimal <defs> should run the purger twice (or until Defs removed reaches 0). Loop until the metric stabilises.
Frequently asked questions
Is there a REST API endpoint for batch defs purging?
No. The purger needs a DOM, so it is not in the server-safe set — the engine refuses it with an explicit "not exposed via the API" error. Automate through the JAD desktop runner (a runner-builtin Pro operation with a headless browser) or by scripting the browser tool.
How do I process a whole folder?
Loop over the folder and dispatch one job per file — the batching is your loop, not a server feature. Each job takes a single SVG and an empty options object and emits <stem>-purged.svg.
Can I preserve specific def ids during automation?
No — the tool has no options, including no preserve list. Any preserve parameter is ignored. Keep files whose defs are referenced externally out of the purge set, or re-add the def after purging.
How does it handle a gradient referenced from inside a filter?
It keeps it. The reference scan reads the entire serialized document, so a url(#grad) written inside a <filter> counts as a reference. This indirect case works automatically.
Does SVGO do the same thing?
SVGO has plugins like cleanupIds and custom plugins that approximate removing unreferenced ids, but its detection rules differ from this tool's exact url(#id) + (xlink:)?href="#id" document scan. If you already run SVGO in Node, validate that its output matches your expectations before swapping.
Why might purging break an icon in CI?
If a def is referenced only from external CSS or JavaScript, the document-only scan sees it as dead and removes it. Always gate the pipeline on a visual-regression diff so any such false positive fails the build instead of shipping.
Can I run it as a pre-commit hook?
Yes — collect staged .svg files with git diff --cached --name-only, run each through the runner, and re-git add them. This keeps dead defs out of every commit.
Does the runner upload my files?
No. The runner executes locally on your machine; nothing is uploaded. The browser fallback is equally local (the web tool shows a 0 bytes uploaded badge).
What does each run report?
Defs removed: N plus original and output byte sizes. Log these per file to track which icons carried dead weight and to prove the cleanup in CI output.
Do I need two passes?
For deep def-to-def chains, yes. A single pass keeps a def that is referenced only inside another def that is itself being removed. Loop the purger until Defs removed is 0 for a fully minimal result.
What happens if a file exceeds the size limit?
It is rejected before processing with a tier-limit message. The Pro per-file ceiling is 50 MB. Files that big usually embed base64 raster — the purger does not process that payload anyway.
Can I combine purging with minification in one pipeline?
Yes, and order matters. Purge first so dead <defs> are gone, then run the Pro-Minifier and Precision Tuner on the smaller markup.
Privacy first
Every JAD SVG tool runs entirely in your browser using the DOM API and Canvas. Your SVG files never leave your device — verified by zero outbound network requests during processing.