Batch Convert SVG to AI With Artboard Clipping Masks
Free Illustrator script that converts folders of SVG files to editable, PDF-compatible AI files and clips each layer to the artboard.
Download illustrator-batch-svg-to-ai-with-clipping-mask.jsxJavaScript (ExtendScript) · 187 lines · 9 KB · free
SVG templates often have shapes that run past the edge of the artboard. In a browser they are cut off cleanly, but in Illustrator and Canva the overflow shows. This script converts a folder of SVG files to .ai and hides the overflow with a clipping mask on every layer, while keeping everything editable.
What it does
For every .svg in the folder you choose and its subfolders, the script:
- adds a clipping mask the exact size of the artboard to each layer, in a group named
Artboard_Clip - keeps layers, shapes and live text editable. Fonts are not converted to outlines.
- saves an
.aifile with the same name in a folder namedIllustratornext to the SVG files - saves the
.aias PDF-compatible, which Canva and other apps need in order to import it - optionally saves the clipping mask back into the SVG file as well
It will not clip a layer twice, so it is safe to run again.
How to use it
- If your SVG files contain live text, install the fonts they use and restart Illustrator.
- Run the script in Illustrator (see below).
- Choose the root folder that holds your SVG files.
- Replace .ai files that already exist? Click Yes to rebuild them or No to skip them.
- Also save the clipping mask into the original SVG files? Click Yes to update the SVG files or No to leave them untouched.
- Read the summary when it finishes.
If you answer Yes to the question about SVG files, your original SVG files are rewritten. Keep a copy of the folder first.
How to run an Illustrator script
- Download the script with the button on this page.
- Open Adobe Illustrator. No document needs to be open.
- Go to File > Scripts > Other Script... (Ctrl+F12 on Windows, Cmd+F12 on Mac).
- Choose the downloaded
.jsxfile.
To keep the script in the menu, copy it into Illustrator's Presets > en_US > Scripts folder inside the Illustrator application folder and restart Illustrator. It then appears under File > Scripts.
Illustrator may warn that scripts can change your files. That is normal for any script. This one's full code is shown at the bottom of the page so you can read what it does.
Who it is for
- Template sellers who design in SVG and need to deliver Illustrator files as well
- Canva users importing
.aifiles, which must be PDF-compatible - Anyone with artwork that bleeds past the artboard and should look tidy when opened
Questions
Why is the text in my AI file in the wrong font?
The font is not installed on your computer. The script keeps text live, so Illustrator substitutes a font when the original is missing. Install the fonts and run the script again, answering Yes to replace existing files.
Can I remove the clipping mask later?
Yes. Select the Artboard_Clip group and choose Object > Clipping Mask > Release.
Does it work on SVG icons?
It works, but simple icons do not need it. For plain format conversion, use batch SVG to EPS or open the SVG directly.
The code
This is the complete script. Nothing else is downloaded or installed.
// illustrator-batch-svg-to-ai-with-clipping-mask.jsx
// Free script from LinearAndLoom Icons: https://linearandloomicons.netlify.app/scripts/
// Provided as is. Try it on a copy of your files first.
/* SVG to AI Converter for Adobe Illustrator (with artboard clipping mask)
------------------------------------------------------------
HOW TO RUN
1. If your SVG files contain live text, install the fonts they use first, then restart Illustrator.
2. In Illustrator: File > Scripts > Other Script... and choose this file.
3. Pick the ROOT folder when asked (the folder that holds your SVG files, or any parent folder).
WHAT IT DOES, FOR EVERY .svg IN THE FOLDER AND ITS SUBFOLDERS
1. Opens the SVG.
2. Adds a clipping mask the exact size of the artboard to every layer, so anything that
sticks out past the artboard edge is hidden. Layers, text and shapes stay editable
(each layer gets one clip group named "Artboard_Clip").
3. Saves the SVG again WITH the clipping mask (text stays live text, fonts are not outlined).
4. Saves an .ai file with the same name into a folder named "Illustrator" next to the SVGs.
Saved as PDF-compatible .ai (needed so the files can also be imported into Canva).
NOTES
- At the start you can choose whether existing .ai files should be replaced
(choose YES if you already converted files with an older version of this script).
- Layers that are already clipped ("Artboard_Clip") are not clipped twice, so it is safe to run again.
- Shows a summary when finished.
*/
#target illustrator
(function () {
if (app.name.indexOf("Illustrator") < 0) { alert("Please run this script in Adobe Illustrator."); return; }
var root = Folder.selectDialog("Select the ROOT folder that contains your SVG files");
if (!root) { return; }
var overwriteAi = confirm("Replace .ai files that already exist?\n\nYES = replace them (recommended if you converted before, so they get the clipping mask)\nNO = skip them");
var updateSvg = confirm("Also save the clipping mask into the original SVG files?\n\nYES = SVG files are updated with the clipping mask (recommended)\nNO = only the .ai files get the clipping mask");
var previousLevel = app.userInteractionLevel;
app.userInteractionLevel = UserInteractionLevel.DONTDISPLAYALERTS;
var CLIP_NAME = "Artboard_Clip";
var converted = 0, skipped = 0, foldersMade = 0, svgUpdated = 0, failed = [];
function isSvg(f) { return (f instanceof File) && /\.svg$/i.test(f.name) && f.name.charAt(0) !== "."; }
function aiOptions() {
var o = new IllustratorSaveOptions();
o.pdfCompatible = true; // required for Canva import and for previews in other apps
o.embedLinkedFiles = true;
o.embedICCProfile = false;
o.compressed = true;
o.fontSubsetThreshold = 100; // embed the fonts used (as subsets) inside the PDF-compatible part
return o;
}
function svgOptions() {
var o = new ExportOptionsSVG();
o.DTD = SVGDTDVersion.SVG1_1;
o.fontType = SVGFontType.SVGFONT; // keep text as real, editable text (not outlines)
o.fontSubsetting = SVGFontSubsetting.None; // use the installed fonts, do not embed glyphs
o.embedRasterImages = true;
o.cssProperties = SVGCSSPropertyLocation.PRESENTATIONATTRIBUTES;
o.documentEncoding = SVGDocumentEncoding.UTF8;
o.coordinatePrecision = 3;
o.preserveEditability = false;
o.includeFileInfo = false;
o.slices = false;
o.sVGAutoKerning = false;
o.sVGTextOnPath = false;
try { o.saveMultipleArtboards = false; } catch (e) {}
return o;
}
function alreadyClipped(layer) {
for (var i = 0; i < layer.groupItems.length; i++) {
var g = layer.groupItems[i];
if (g.name === CLIP_NAME && g.clipped && g.parent === layer) { return true; }
}
return false;
}
// Puts all items of one layer into a group clipped to the artboard rectangle.
function clipLayer(layer, ab) {
for (var s = 0; s < layer.layers.length; s++) { clipLayer(layer.layers[s], ab); } // sublayers get their own clip
var wasLocked = layer.locked, wasVisible = layer.visible;
layer.locked = false; layer.visible = true;
try {
var n = layer.pageItems.length;
if (n === 0 || alreadyClipped(layer)) { return; }
var items = [];
for (var i = 0; i < n; i++) { items.push(layer.pageItems[i]); } // index 0 = top of the stack
var grp = layer.groupItems.add();
grp.name = CLIP_NAME;
grp.move(layer, ElementPlacement.PLACEATBEGINNING);
// move bottom-first, each to the top of the group, so the original stacking order is kept
for (var k = items.length - 1; k >= 0; k--) {
var it = items[k];
if (it === grp) { continue; }
var wasItLocked = false, wasHidden = false;
try { wasItLocked = it.locked; it.locked = false; } catch (e1) {}
try { wasHidden = it.hidden; it.hidden = false; } catch (e2) {}
it.move(grp, ElementPlacement.PLACEATBEGINNING);
try { if (wasHidden) { it.hidden = true; } } catch (e3) {}
try { if (wasItLocked) { it.locked = true; } } catch (e4) {}
}
// artboardRect = [left, top, right, bottom]
var r = grp.pathItems.rectangle(ab[1], ab[0], ab[2] - ab[0], ab[1] - ab[3]);
r.filled = false; r.stroked = false;
r.name = "Artboard_Clip_Path";
r.move(grp, ElementPlacement.PLACEATBEGINNING); // clipping path must be the top item
grp.clipped = true;
} finally {
layer.visible = wasVisible; layer.locked = wasLocked;
}
}
function addClipping(doc) {
var ab = doc.artboards[doc.artboards.getActiveArtboardIndex()].artboardRect;
for (var i = 0; i < doc.layers.length; i++) { clipLayer(doc.layers[i], ab); }
}
function walk(folder) {
var items = folder.getFiles();
var svgs = [];
var i;
for (i = 0; i < items.length; i++) {
var it = items[i];
if (it instanceof Folder) {
var n = it.name.toLowerCase();
if (n !== "illustrator" && n !== "__macosx" && n.charAt(0) !== ".") { walk(it); }
} else if (isSvg(it)) {
svgs.push(it);
}
}
if (svgs.length === 0) { return; }
var out = new Folder(folder.fsName + "/Illustrator");
if (!out.exists) { out.create(); foldersMade++; }
svgs.sort(function (a, b) { return a.name < b.name ? -1 : (a.name > b.name ? 1 : 0); });
for (i = 0; i < svgs.length; i++) {
var svg = svgs[i];
var target = new File(out.fsName + "/" + decodeURI(svg.name).replace(/\.svg$/i, ".ai"));
if (target.exists && !overwriteAi) { skipped++; continue; }
var doc = null;
try {
doc = app.open(svg);
addClipping(doc);
if (updateSvg) {
// export to a temporary file first, then replace the original only if the export worked
var tmp = new File(folder.fsName + "/~clip_tmp_" + decodeURI(svg.name));
doc.exportFile(tmp, ExportType.SVG, svgOptions());
if (tmp.exists && tmp.length > 0) {
var path = svg.fsName, name = svg.name;
svg.remove();
tmp.rename(decodeURI(name));
svg = new File(path);
svgUpdated++;
}
}
if (target.exists) { target.remove(); }
doc.saveAs(target, aiOptions());
doc.close(SaveOptions.DONOTSAVECHANGES);
converted++;
} catch (e) {
failed.push(decodeURI(svg.name) + " (" + e + ")");
try { if (doc) { doc.close(SaveOptions.DONOTSAVECHANGES); } } catch (e2) {}
}
}
}
try { walk(root); } finally { app.userInteractionLevel = previousLevel; }
var msg = "SVG to AI - finished\n\n" +
"Converted to .ai (with clipping mask): " + converted + " file(s)\n" +
"SVG files updated with clipping mask: " + svgUpdated + "\n" +
"Already existed (skipped): " + skipped + "\n" +
"New 'Illustrator' folders: " + foldersMade + "\n";
if (failed.length) { msg += "\nCould not convert " + failed.length + " file(s):\n" + failed.slice(0, 15).join("\n"); }
alert(msg);
})();
Download illustrator-batch-svg-to-ai-with-clipping-mask.jsxJavaScript (ExtendScript) · 187 lines · 9 KB · free
These scripts are free. If one saved you time, you can say thanks by buying a pack from the LinearAndLoom Etsy shop.


