Skip to main content
Participant
December 22, 2025
Answered

InDesign becomes unresponsive when running ‘Missing Glyphs’ script on emoji-heavy Document.

  • December 22, 2025
  • 1 reply
  • 425 views
Hello I am Niven,
 
I was hoping to get some help regarding a script which malfunctions in my situation.
 
I use InDesign Mail Merge on a regular basis for my work with like 600 to 800+ Pages per Document which has multiple languages and emojis and the script I got from Peter Kahrel to Manage Multiple Missing Glyphs at one time is not working as it probably worked for other people on some YouTube Tutorials. As I run the script and select a replacement font (Noto Emoji Regular) for the Missing Glyphs the script runs at first but after 2 - 3 Minutes InDesign stops responding. No error message is shown. Manually replacing the missing glyphs with ‘Noto Color Emoji’ works correctly, which suggests the issue may be related to the script or my PC.
 
Also I would like to add that the people using the script flawlessly were using it on a macOS and I am on a Windows PC.
I use Adobe InDesign 2025 version with all updates installed.
 
I came to know about the script from Adobe Community Forums itself which is here 
 
 
The Script is as follows :
 
(function () {
if (parseInt(app.version) < 6) {
alert('This script requires InDesign CS4 or later.');
exit();
}
 
if (app.documents.length == 0) {
alert('Please open a document');
exit();
}
 
function find_fonts() {
var known = {};
var typefaces = [];
var fontfamilies = app.fonts.everyItem().fontFamily;
for (var i = 0; i < fontfamilies.length; i++) {
if (!known[fontfamilies[i]]) {
known[fontfamilies[i]] = true;
typefaces.push(fontfamilies[i]);
}
}
return typefaces;
}
 
function buildListCharacterStyles(scope, list, str, path) {
var styles = scope.characterStyles.everyItem().getElements();
for (var i = 0; i < styles.length; i++) {
if (styles[i] != app.documents[0].characterStyles[0]) {
var temp = list.add('item', styles[i].name + (str == '' ? '' : ' (' + str + ')'));
temp.id = styles[i].id;
temp.path = path + styles[i].name;
}
}
for (var j = 0; j < scope.characterStyleGroups.length; j++) {
buildListCharacterStyles(
scope.characterStyleGroups[j],
list,
str + (str == '' ? '' : ':') + scope.characterStyleGroups[j].name,
path + scope.characterStyleGroups[j].name + '%%'
);
}
}
 
function get_data() {
var fontnames = find_fonts();
 
var w = new Window('dialog {text: "Missing glyphs", properties: {closeButton: false}}');
var main = w.add('panel {alignChildren: "left"}');
 
var fontgroup = main.add('group');
var replacefonts = fontgroup.add('checkbox {text: "Replace missing glyphs with font:"}');
var replacement_font = fontgroup.add('dropdownlist', undefined, fontnames);
 
var cstylegroup = main.add('group');
var applyStyle = cstylegroup.add('checkbox {text: "Apply character style: "}');
var charStyles = cstylegroup.add('dropdownlist');
charStyles.preferredSize.width = 200;
 
var display = main.add('checkbox {text: "Display missing glyphs and fonts"}');
 
var buttons = w.add('group {alignment: "right"}');
buttons.add('button {text: "OK", name: "ok"}');
buttons.add('button {text: "Cancel", name: "cancel"}');
 
replacefonts.onClick = function () {
applyStyle.value = !replacefonts.value;
};
 
replacement_font.onChange = function () {
if (!replacefonts.value) {
replacefonts.notify();
}
};
 
applyStyle.onClick = function () {
replacefonts.value = !applyStyle.value;
};
 
charStyles.onChange = function () {
if (!applyStyle.value) {
applyStyle.notify();
}
};
 
display.onClick = function () {
if (display.value) {
replacefonts.value = applyStyle.value = false;
}
};
 
var minion = replacement_font.find('Minion Pro');
replacement_font.selection = minion ? minion : 0;
replacefonts.value = 1;
 
var buffer = '';
var current = replacement_font.selection.text;
 
replacement_font.onActivate = function () {
buffer = '';
current = replacement_font.selection.text;
};
 
replacement_font.addEventListener('keydown', function (k) {
if (k.keyName == 'Backspace') {
buffer = buffer.replace(/.$/, '');
if (buffer.length == 0) {
buffer = current;
}
} else {
buffer += k.keyName.toLowerCase();
}
var i = 0;
while (i < fontnames.length - 1 && fontnames[i].toLowerCase().indexOf(buffer) != 0) {
++i;
}
if (fontnames[i].toLowerCase().indexOf(buffer) == 0) {
replacement_font.selection = i;
}
});
 
w.onShow = function () {
buildListCharacterStyles(app.activeDocument, charStyles, '', '');
if (charStyles.items.length > 0) {
charStyles.selection = 0;
}
};
 
if (w.show() == 2) {
return null;
}
 
// 🛠️ Prevent null reference
if ((applyStyle.value || (!replacefonts.value && !display.value)) && !charStyles.selection) {
alert("Please select a character style.");
return null;
}
 
return {
replace: replacefonts.value,
replacement_font: replacement_font.selection ? replacement_font.selection.text : "",
applyStyle: applyStyle.value,
character_style: charStyles.selection
? app.documents[0].characterStyles.itemByID(charStyles.selection.id)
: null,
display: display.value,
};
}
 
function replace_missing_glyphs(data) {
var docFonts = app.activeDocument.fonts.everyItem().getElements();
var errormsg = '';
 
app.findGlyphPreferences = null;
for (var i = 0; i < docFonts.length; i++) {
if (docFonts[i].status == FontStatus.INSTALLED && docFonts[i].isValid) {
app.findGlyphPreferences.glyphID = 0;
app.findGlyphPreferences.appliedFont = docFonts[i].fontFamily;
app.findGlyphPreferences.fontStyle = docFonts[i].fontStyleName;
var found = app.activeDocument.findGlyph();
for (var j = 0; j < found.length; j++) {
if (data.replace) {
found[j].appliedFont = data.replacement_font;
} else if (data.applyStyle && data.character_style) {
found[j].appliedCharacterStyle = data.character_style;
}
}
} else {
try {
errormsg += docFonts[i].fontFamily + '\r';
} catch (_) {}
}
}
 
if (errormsg.length > 1) {
errormsg = 'The following fonts are not installed\n(or have an illegal font style specified)\nand were skipped:\n\n' + errormsg;
alert(errormsg);
}
}
 
function list_missing_glyphs() {
var docFonts = app.activeDocument.fonts.everyItem().getElements();
var report = '';
 
for (var i = 0; i < docFonts.length; i++) {
if (docFonts[i].status != FontStatus.INSTALLED) {
report += '[' + docFonts[i].name + ']\r';
} else {
app.findGlyphPreferences = null;
app.findGlyphPreferences.glyphID = 0;
app.findGlyphPreferences.appliedFont = docFonts[i].fontFamily;
app.findGlyphPreferences.fontStyle = docFonts[i].fontStyleName;
var found = app.activeDocument.findGlyph();
if (found.length > 0) {
var known = {};
report += docFonts[i].fontFamily + ' (' + docFonts[i].fontStyleName + ')\r';
for (var j = 0; j < found.length; j++) {
var miss = get_hex(found[j]);
if (!known[miss]) {
report += found[j].contents + '\t' + miss + '\r';
known[miss] = true;
}
}
report += '\r';
}
}
}
display_missing_glyphs(report);
}
 
function get_hex(ch) {
function pad(n) {
return ('0000' + n).slice(-4);
}
try {
if (ch.contents.length === 2) {
var H = parseInt(ch.contents.charCodeAt(0).toString(16), 16);
var L = parseInt(ch.contents.charCodeAt(1).toString(16), 16);
var s = ((H - 0xD800) * 0x400) + (L - 0xDC00) + 0x10000;
return '\\x{' + s.toString(16).toUpperCase() + '}';
}
var s = ch.contents.charCodeAt(0).toString(16);
return '\\x{' + pad(s).toUpperCase() + '}';
} catch (_) {
return 'U+????';
}
}
 
function display_missing_glyphs(s) {
var w = new Window('dialog {text: "Missing glyphs", properties: {closeButton: false}}');
var e = w.add('edittext', undefined, s.length == 0 ? 'No missing glyphs.' : s, {
multiline: true,
scrolling: true,
});
e.maximumSize.height = w.maximumSize.height - 150;
 
var b = w.add('group');
b.add('button {text: "Close", properties: {name: "ok"}}');
var save = b.add('button {text: "Save"}');
 
save.onClick = function () {
var outfile = File('~/Desktop/' + app.activeDocument.name.replace(/\.indd$/, '_missing_glyphs.txt'));
outfile.encoding = 'UTF-8';
outfile.open('w');
outfile.write(e.text);
outfile.close();
outfile.execute();
};
 
w.show();
}
 
function main() {
app.findChangeGlyphOptions.includeFootnotes = true;
var data = get_data();
if (!data) return;
 
if (data.replace || data.applyStyle) {
replace_missing_glyphs(data);
}
if (data.display) {
list_missing_glyphs();
}
}
 
main();
})();
 
Regards,
Niven Wadke.
Correct answer Joel Cherney

NivenWadke_1-1766457129638.png

 

This was the error that InDesign showed me when I ran the latest script from here...
https://creativepro.com/files/kahrel/indesign/missing_glyphs.html


I actually had reason to ask myself the other day "How could I search for emoji only, by their Unicode values?" My client's internal tool was choking on any non-Chinese text with a Unicode value above FFFF, and so they were using the Preflight panel with a custom preflight profile that only looked for missing glyphs. I spent a few minutes clicking around on Stack Exchange before I came up with this query, which you can use in the "Find what" field in the GREP tab of your Find/Change dialog:

[\x{1f300}-\x{1f5ff}\x{1f900}-\x{1f9ff}\x{1f600}-\x{1f64f}\x{1f680}-\x{1f6ff}\x{2600}-\x{26ff}\x{2700}-\x{27bf}\x{1f1e6}-\x{1f1ff}\x{1f191}-\x{1f251}\x{1f004}\x{1f0cf}\x{1f170}-\x{1f171}\x{1f17e}-\x{1f17f}\x{1f18e}\x{3030}\x{2b50}\x{2b55}\x{2934}-\x{2935}\x{2b05}-\x{2b07}\x{2b1b}-\x{2b1c}\x{3297}\x{3299}\x{303d}\x{2122}\x{23f3}\x{24c2}\x{23e9}-\x{23ef}\x{25b6}\x{23f8}-\x{23fa}]

This should capture almost all emoji - it's based off of this list. The exceptions are few in number; if someone were to use the emoji version of the copyright symbol (©️), the registered symbol (®️), the trademark symbol (™️), or the emoji versions of numerals (0️ through9️) then the above query would not catch it. 

 

In your shoes, I'd make a character style with my preferred emoji font, then I'd use the GREP tab of the Find/Change dialog to search for the above query in the "Find what" field. I'd leave the "Change to" field empty, and I'd specify my emoji-font character style in the "Change format" area. Once that operation was complete, then I'd cook up a custom preflight profile that only showed me missing glyphs, which would either help me find anything that the query missed, or any uses of emoji numbers, or any other non-emoji missing glyph throughout the document. 

1 reply

Peter Kahrel
Community Expert
Community Expert
December 22, 2025

You don't seem to use the latest version of the script, so start by trying that one, though I can't imagine that it'll make much difference.

 

The better approach in your case is probably to run the script against your database, which is undoubtedly much smaller than the file created by the merge.

Participant
December 23, 2025

Hi Peter,

Thanks for the reply. Just to clarify — when you say the newer script version likely won’t make much difference, are you referring to performance limitations on large merged documents?

And by running the script against the database, do you mean preprocessing the source data (Excel/CSV) before the Mail Merge rather than the final InDesign file?

I’d appreciate any clarification on how you’d recommend handling emojis in this kind of workflow.

Best regards,
Niven

Participant
December 23, 2025

NivenWadke_1-1766457129638.png

 

This was the error that InDesign showed me when I ran the latest script from here...
https://creativepro.com/files/kahrel/indesign/missing_glyphs.html