How to automate svg filter injection across multiple icon files
- Step 1Pick one preset and intensity for the set — Decide the look once: e.g. dropshadow at intensity 6. Every file in the run uses these two values — the tool exposes nothing else, which is what keeps the set uniform.
- Step 2Stage the input files — Collect the SVGs into a folder. Stay within your tier's per-file size and batch-file count (Pro: 50 MB, 20 files; Pro Media: 200 MB, 100; Developer: unlimited).
- Step 3Iterate over the files — Loop over the folder and run the injector on each SVG with the same
{ filterPreset, filterIntensity }. There is no filter-map or glob endpoint — automation is straightforward iteration through the runner-builtin tool. - Step 4Normalize the output names — Each run yields
<stem>-<preset>.svg. Keep that suffix or rename consistently so the build can map originals to filtered versions. - Step 5Spot-check shape coverage — Open a few results across different icon silhouettes. A fixed intensity reads differently on a thin glyph vs. a solid block — if some icons look heavy, split the run into groups with different intensities.
- Step 6Chain post-processing — Pipe results through svg-pro-minifier to shrink, then svg-sprite-builder if you want a single sprite — the embedded filter survives both.
SVG batch limits by tier
Per-file size and batch-file caps that apply to SVG tools, including the filter injector. The injector itself requires Pro to run.
| Tier | Per-file size | Batch files | Notes |
|---|---|---|---|
| Free | 5 MB | 1 | Injector is Pro-gated; free covers other SVG tools only |
| Pro | 50 MB | 20 | Minimum tier for the filter injector |
| Pro Media | 200 MB | 100 | Best fit for large icon libraries |
| Developer | 2 GB | unlimited | Scripted pipelines over whole repos |
| Enterprise | unlimited | unlimited | No documented per-file or batch cap |
What batch automation can and cannot do
Set expectations against the actual implementation — there is no per-file filter-map, glob matcher, or ZIP-returning batch endpoint.
| Capability | Supported? | How it really works |
|---|---|---|
| Apply one preset across many files | Yes | Iterate the runner-builtin tool with the same { filterPreset, filterIntensity } |
| Different preset per file in one call | No | Run separate passes, one preset each, partitioning files by intended look |
Glob patterns like icon-*.svg | No such endpoint | Do the globbing in your own script, then loop the matched files |
replace_existing flag to strip old filters | No | The injector skips groups that already have filter=; pre-clean with svg-unused-defs-purger if needed |
| ZIP of all results from one request | No | Each run returns one SVG; your script collects them |
| Deterministic, reproducible output | Yes | Same inputs always produce the same <filter> and id |
Cookbook
Real iteration patterns — the injector processes one file per call, so batching is a loop, not a special mode.
Uniform drop shadow over a folder
One preset and intensity, looped over every SVG. Each call returns one filtered SVG named <stem>-dropshadow.svg.
for each file in ./icons/*.svg:
run svg-filter-injector
input: file
options: { filterPreset: "dropshadow", filterIntensity: 6 }
-> writes ./out/<stem>-dropshadow.svg
Result: 24 icons, identical feDropShadow (dx=3, dy=6, stdDeviation=3, flood-opacity 0.4).Two looks in one build via partitioning
There is no per-file filter-map, so split the file list yourself and run two passes. Logos get a glow; UI icons get a subtle shadow.
Pass A (logos):
files = ./brand/*.svg
options = { filterPreset: "glow", filterIntensity: 5 }
Pass B (ui icons):
files = ./ui/*.svg
options = { filterPreset: "dropshadow", filterIntensity: 3 }
# Your script decides the partition; the tool just applies one preset per call.Pre-clean then inject
Because the injector skips any <g> that already has filter=, strip stale filters first if you are re-skinning an already-processed set.
Step 1: svg-unused-defs-purger over ./icons (removes orphaned <filter> defs)
Step 2 (manual or scripted): remove existing filter= on root groups
Step 3: svg-filter-injector { glow, 4 } over the cleaned files
# Otherwise the new filter is added to <defs> but never attached to a pre-filtered group.Inject, then minify, then sprite
Embedded SVG filters are plain markup, so they survive a downstream optimize and sprite build.
icons/*.svg
-> svg-filter-injector { dropshadow, 5 } (effect baked in)
-> svg-pro-minifier (size down, <filter> kept)
-> svg-sprite-builder (one sprite, each <symbol> keeps its filter)Size-guarding the batch
Enforce the per-file cap before dispatch so a single oversized file does not fail the run. Pro is 50 MB per file and 20 files per batch.
limit = tier == 'pro' ? 50_000_000 : tier == 'pro_media' ? 200_000_000 : Infinity
batchCap = tier == 'pro' ? 20 : tier == 'pro_media' ? 100 : Infinity
files = list('./icons').filter(f => size(f) <= limit).slice(0, batchCap)
for f in files: run svg-filter-injector { glow, 4 }Edge cases and what actually happens
Expecting a filter-map of file→preset
Not supportedThere is no filter_map, glob matcher, or per-file config. The tool takes one filterPreset and one filterIntensity per call. Do the matching in your own script and run separate passes per look.
Expecting a ZIP from one request
Not supportedEach invocation processes one SVG and returns one SVG. Collect and archive results in your pipeline; the tool does not bundle multiple outputs.
Re-skinning files that already have a filter
Skipped attachmentThe injector only attaches to a <g> without an existing filter=. On already-filtered icons it adds the new <filter> to <defs> but does not re-target the group, so the effect may not change. Strip the old filter first.
One fixed intensity reads wrong on some shapes
By designIntensity is uniform across a pass. A thin glyph and a solid block respond differently to the same stdDeviation. Partition the set and run groups with different intensities for a consistent perceived weight.
File exceeds the tier per-file limit
413 / rejectedA file over the tier cap (5 MB free, 50 MB pro, 200 MB pro_media, 2 GB developer) is rejected with a per-job limit error before processing. Pre-filter the batch by size, or upgrade the tier.
Batch exceeds the file-count cap
RejectedPro allows 20 batch files, Pro Media 100. Beyond that, chunk the run into multiple batches or move to Developer for unlimited counts. Free tier is single-file and cannot run the injector at all.
Calling the tool on the free tier via the API
403 / tier errorThe injector is registered as tierRequired: pro (runner-builtin). A free-tier caller is blocked. Authenticate as Pro or higher.
Calling a browser-only SVG tool through the same path
Engine errorOnly tools in the server-safe set run headless. The filter injector is in that set, but if your pipeline also hits a browser-only tool the engine throws 'not exposed via the API — requires browser-side processing'. Keep batch steps to server-safe tools.
Duplicate filter ids after repeated passes
CleanableRe-running the same preset twice can leave two jad-filter-<preset> defs. Run svg-unused-defs-purger to drop the orphan, or design the pipeline to inject once.
Frequently asked questions
Is there a dedicated batch filter API?
No special batch endpoint. The injector is a server-safe, runner-builtin tool that processes one SVG per call. Batch automation means looping your file list through the same preset and intensity.
Can I apply different filters to different icons in one call?
No. There is no per-file filter-map. Partition your files in your own script and run one pass per look — for example glow over logos, drop shadow over UI icons.
Does it support glob patterns?
Not in the tool. Do the globbing yourself (e.g. expand icon-*.svg in your script) and iterate the matched files through the injector.
Will it replace an existing filter?
No replace_existing option exists. The injector skips any group that already has a filter= attribute, so to re-skin you must strip the old filter first, then inject.
How many files can I process at once?
By tier: Pro 20 files / 50 MB each, Pro Media 100 / 200 MB, Developer unlimited / 2 GB, Enterprise unlimited. Free tier is single-file and cannot run the injector (it is Pro-gated).
Is the output deterministic?
Yes. The same preset and intensity always produce the same <filter> markup and the id jad-filter-<preset>, which is what keeps a whole set consistent and makes results reproducible in CI.
Can I run it without the browser?
Yes. It is in the server-safe set and runs as a runner-builtin for Pro+ users, so you can drive it from the local runner in a script rather than the web UI.
What tier is required?
Pro at minimum — the tool is registered tierRequired: pro. Larger batches and bigger files need Pro Media or Developer.
How are output files named?
Each result is <original-stem>-<preset>.svg. Keep the suffix or rename consistently so your build can pair originals with filtered versions.
Can I sprite the filtered icons afterward?
Yes. The effect is embedded markup, so pass the results to svg-sprite-builder; each <symbol> keeps its filter. Minify first with svg-pro-minifier if size matters.
Why do some icons look heavier than others after a uniform pass?
A single intensity is a fixed stdDeviation/offset, which reads differently across silhouettes. Group icons by visual weight and run each group at a tuned intensity.
How do I avoid duplicate filter defs?
Inject once per file. If a pipeline accidentally runs twice, clean orphaned <filter> defs with svg-unused-defs-purger.
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.