fontbom
Font bill of materials for mobile apps and codebases.
fontbom scans .ipa, .apk, .aab, .app, .xcframework, .zip files and source
repositories for bundled fonts, extracts their license metadata, and reports which fonts are
open-licensed, commercial, embedding-restricted, or unknown. It also cross-references fonts
against code so you can see fonts that are bundled but never used, and fonts that code
references but the bundle does not contain.
Existing font license scanners cover websites and PDFs. Nothing covered app binaries.
Fully offline. Nothing is uploaded.
fontbom reports metadata found inside font files and adjacent license files. It is not legal advice. Verify license terms with the font vendor or your legal team.
Install
pip install fontbom
Requires Python 3.11 or newer.
Usage
fontbom scan App.ipa
fontbom scan app-release.aab --format markdown --output fonts.md
fontbom scan . --format csv
fontbom scan App.ipa --fail-on unknown,commercial,restricted
Inputs: a directory, .ipa, .app, .apk, .aab, .xcframework, .zip, or a single font
file. Nested archives and bundles (.framework, .bundle, .aar, .jar, zip inside zip) are
expanded, with limits on depth, total size and member count.
Exit codes:
| Code | Meaning |
|---|---|
| 0 | Scan completed and no --fail-on status matched |
| 1 | At least one font matched a --fail-on status |
| 2 | Usage error, unreadable input, unsafe archive member, or a limit was exceeded |
--fail-on accepts open, commercial, restricted, unknown and unreferenced.
--jobs N sets the worker processes used to search large binaries; the default is the number
of CPUs. Small scans stay single-process because starting workers costs more than it saves.
When stdout is a terminal the default format is terminal: a color-coded, aligned summary
fitted to the window, with unbundled names grouped and counted. When stdout is piped or
--output is used the default is json. --format overrides either.
The report goes to stdout, or to the file named by --output. Everything else goes to stderr:
a live status line while the scan runs (on by default in a terminal, forced with --progress,
disabled with --no-progress or --quiet) and a one-line summary at the end. Piping stdout
therefore always yields a clean report.
What it reports
For every distinct font (by sha256):
- every path where it appears, including inside vendored frameworks and SDKs, written as
App.ipa!/Payload/App.app/Frameworks/Vendor.framework/Font.ttf - name table IDs 0, 1, 2, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17
- OS/2
fsTypedecoded into an embedding permission, plusachVendIDand the font revision - a license status with the evidence that produced it
- the code references that name it, by family, full name, PostScript name or file name
Plus two gap lists: fonts bundled but unreferenced, and names referenced but not bundled.
License statuses
| Status | Meaning |
|---|---|
open |
License text or URL in the font, or an adjacent license file, matched an open license (OFL-1.1, Apache-2.0, UFL-1.0, MIT, Bitstream Vera, CC0, GPL/LGPL with a copyleft note). SPDX id included. |
commercial |
The font's license text or URL contains explicit EULA wording or points at a known commercial vendor's license page. |
restricted |
fsType says restricted license embedding. Overrides the other statuses; license evidence is still reported. |
unknown |
Everything else. This is the default. fontbom never guesses open. |
Adjacent license files are searched in the font's directory and up to three parent directories,
stopping at the enclosing archive or bundle. Generic files (LICENSE, COPYING) count only when
they sit in the font's own directory, because a repository license describes the code, not the
fonts. Font-specific files (OFL.txt, UFL.txt, or any file that mentions fonts) count up to
the distance limit.
Code references
| Ecosystem | What is scanned |
|---|---|
| iOS | UIFont(name:), fontWithName:, SwiftUI Font.custom, UIAppFonts in Info.plist (XML or binary), Bundle.url(forResource:withExtension:) for Core Text registration, font file literals, storyboard and xib fontDescription |
| Android | @font/x, R.font.x, android:fontFamily, app:fontFamily, Typeface.createFromAsset, font file literals |
| Flutter | pubspec.yaml fonts: families and assets, Dart fontFamily: |
| React Native | require('…ttf'), import … from '…ttf', fontFamily: in styles |
| Web | @font-face families and src URLs, Google Fonts stylesheet URLs (parsed, never fetched) |
| Binaries | Family, full and PostScript names of discovered fonts searched as ASCII and UTF-16 strings in Mach-O executables, classes.dex, resources.arsc, resources.pb, .so, .dylib and compiled nibs. Reported at low confidence. |
Compiled Swift, Kotlin and Android binary XML are not decompiled. A font that is loaded by a name built at runtime can appear as unreferenced.
Output formats
terminal: for humans at a terminal. Summary, aligned font table, unreferenced fonts, and the top referenced-but-unbundled names grouped by name with counts.json: stable, sorted, with aschema_versionfield. Suitable for diffing and for feeding other tools.csv: one row per font, disclaimer as a leading#comment.markdown: summary, font table, gap lists. Suitable for pull-request comments.
Roadmap
Not in this release: SARIF output, CycloneDX and SPDX output, a license-evidence file linking fonts to purchase records, a curated font-license knowledge base, glyph fingerprinting for renamed fonts.
Development
python3.12 -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/ruff check . && .venv/bin/ruff format --check . && .venv/bin/mypy && .venv/bin/pytest
Tests build fonts at runtime with fontTools' FontBuilder and build app bundles with zipfile.
The only committed fonts are two small open-licensed fonts from Google Fonts, with their
license files, under tests/fixtures/fonts/. Never commit proprietary fonts or real app
binaries.
License
Apache-2.0. Fixture fonts keep their own licenses: Press Start 2P (OFL-1.1) and Chewy (Apache-2.0).
Release files for fontbom 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fontbom-0.1.0.tar.gz | 131.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fontbom-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 175.5 kB
Release files / fontbom-0.1.0.tar.gz
| Download URL | fontbom-0.1.0.tar.gz |
|---|---|
| Size | 131.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7bccafc2996f4ad2473467ebfa26ef21a2f88e4b7bc42b1288cfb5364e854518
|
|
BLAKE2b-256 checksum How to use checksums |
7624c97dd3d4da90818550cd7e95073ca8f12b8d20c841b680de0e9d397f7a03
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency logRelease files / fontbom-0.1.0-py3-none-any.whl
| Download URL | fontbom-0.1.0-py3-none-any.whl |
|---|---|
| Size | 43.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
da52ef13a3ec4f7fb8acec02ce65433ac8ac9db149825d8c17c7927b68ca6c92
|
|
BLAKE2b-256 checksum How to use checksums |
15456c38710f8d7147823489446d75601bd6698ba1a1502264dee68fccec02d5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency log