iGlyph
Bundle a folder of fonts into a single iOS/iPadOS configuration profile. One tap to install all of them.
iOS insanely has no native font installer. You need a .mobileconfig profile. App Store options (iFont, Fontastic) cost money. iGlyph is one pure-stdlib Python file that just does the bundling. No dependencies other than Python itself, and free. If you have the fonts already, and don't want the font gallery features iOS apps provide, this is probably sufficient.
Use it
Point it at a folder of .ttf/.otf files and serve it to your device over the local network:
python3 iglyph.py ./my-fonts --serve
Open the printed URL in Safari on your iPhone/iPad, then install the profile from the prompt (or Settings -> General -> VPN & Device Management). Fonts then appear in Settings -> General -> Fonts and in any app with a font picker (Pages, Keynote, Procreate, etc.).
Prefer to AirDrop or email instead?
python3 iglyph.py ./my-fonts -o MyFonts.mobileconfig
Check what would be bundled without writing anything:
python3 iglyph.py ./my-fonts --list
Options
| Flag | Effect |
|---|---|
-o, --output |
Output path (default: iGlyph.mobileconfig) |
-l, --list |
Show what would be bundled; check for duplicates |
--serve [PORT] |
Serve over HTTP (default port 18888), exits after first download |
--timeout MIN |
Serve timeout in minutes (default: 10) |
--name |
Profile display name shown on install |
--organization |
Organization shown on install |
Notes
- TTF and OTF only. Collections (
.ttc/.otc) and web fonts (.woff/.woff2) aren't supported by iOS — iGlyph rejects them with a clear message. - Duplicate PostScript names get a warning, not an error. iOS keeps one of each; remove duplicates if you want deterministic results.
- Profiles install unsigned and show "Unverified." That's cosmetic — the install works identically. Signing only removes the warning if the cert chains to a CA the device already trusts, which isn't worth the hassle for a one-off tool.
Note
Set the MIME type or Safari won't hand the file to the profile installer. Guess how much not-cursing was involved in figuring this out? Zero, zero non-cursing. Caddy example:
@mobileconfig path *.mobileconfig
header @mobileconfig Content-Type application/x-apple-aspen-config
License
MIT