keynote-parser
keynote-parser is a Python module for unpacking and re-packing
Apple Keynote .key files. It supports Keynote
files generated by Keynote version 14.4 (current as of April 2025).
Keynote uses a proprietary, compressed binary format to store its presentations.
This format is comprised of a zip file containing images and videos, as well as
Snappy-compressed
Protobuf .iwa files containing
metadata, text, and all other definitions used in the presentation.
keynote-parser unpacks these component files into .yaml files in a directory,
making them editable by text editors and/or scripts, then allows re-packing of these
files into a working Keynote archive.
What could you use this for? Well, I use it to allow versioning of Keynote files in Git, which makes diffs more understandable (rather than binary), as well as modifying text in Keynote files in response to external scripts. (e.g.: figures that update from databases before giving a presentation)
Installation
uv pip install keynote-parser
Usage
# Unpack MyPresentation.key into ./MyPresentation/
keynote-parser unpack MyPresentation.key
# Re-pack ./MyPresentation/ into MyPresentation.out.key
keynote-parser pack ./MyPresentation/
# List the files within a Keynote archive
keynote-parser ls MyPresentation.key
# Dump a particular .iwa file into its yaml representation on stdout
keynote-parser cat MyPresentation.key /Index/Slide-00001.iwa
# Replace text within a Keynote file in-place
keynote-parser replace MyPresentation.key --find "hello world" --replace "hello dolly"
Formats
keynote-parser supports reading a list of replacements from a JSON file passed in
as --replacements. This file must have the form:
{
"replacements": [
{
"find": "regexp to search for",
"replace": "string to replace with"
},
...
]
}
This argument can be passed to keynote-parser replace to replace text in a Keynote
file in-place. It can also be passed to keynote-parser pack to pack a directory
into a Keynote file, replacing text along the way.
Replacing Images
The replacements json format can also be used to replace images in a Keynote file.
To do so:
- Use the
keynote-parser lscommand to determine the name of the image to replace. - Set the
findpattern to the image's name, with the-\d\d\dsuffix removed. - Set the
replacefield to the local path to the replacement image.
keynote-parser will automatically rescale the replacement image to fit all of the
sizes of the target image.
Compatibility
Note that between Keynote 10.2 and Keynote 11.2, a number of Protobuf definitions
used by Keynote have changed names. keynote-parser does not yet support
backwards compatibility: it can only read .key files as the
currently-supported Keynote version would, and will write .yaml output with
keys that match the current names of the keys. This means that .yaml files
generated with older versions of keynote-parser may not be readable by with
v1.11.2.1 or higher of keynote-parser.
Until this issue is fixed (if it's ever fixed) - to properly read .yaml files
created by older versions of keynote-parser:
- use an older version of
keynote-parserto read the file - write a
.key(or.iwa) file with that older version - upgrade
keynote-parser - read that resulting
.iwafile in the newer version ofkeynote-parser
Updates
As keynote-parser includes Protobuf definitions extracted from a copy of Keynote,
new versions of Keynote will inevitably create .key files that cannot be read by keynote-parser.
Rebuilding the generated code
The generated Protobuf code is not checked in, so a fresh clone needs to build it once before the tests will run:
python dumper/run.py
This compiles the .proto files already in protos/versions/ using a pinned
copy of protoc, downloaded into .protoc/ on first use. The pin matters: the
generated code is only guaranteed to load under a google.protobuf at least as
new as the protoc that produced it, so building with an arbitrary protoc
from $PATH (Homebrew ships a very recent one) produces code that fails to
import with:
google.protobuf.runtime_version.VersionError: Detected incompatible Protobuf
Gencode/Runtime versions ... Runtime version cannot be older than the linked
gencode version.
To use a specific protoc anyway, pass --protoc /path/to/protoc.
Adding support for a new version of Keynote
As keynote-parser includes Protobuf definitions extracted from a copy of Keynote,
new versions of Keynote will inevitably create .key files that cannot be read by
keynote-parser. When a new version of Keynote is installed, run the following on
that macOS machine to regenerate the mappings and compiled Protobuf files:
PYTHONPATH=$PYTHONPATH:$(pwd) uv run \
--python /opt/homebrew/bin/python3 \
--with rich --with 'protobuf>=3.20.0rc1,<4' \
python dumper/run.py --app-path "/Applications/Keynote.app"
This extracts the .proto files and message registry from the app bundle into
protos/versions/<version>/, then compiles them as in the previous section.
Prerequisites:
- macOS with the new version of Keynote installed
- Homebrew Python:
brew install python@3.13 - LLVM/LLDB matching that Python version:
brew install llvm
protoc is not a prerequisite: it is pinned and downloaded automatically, as
described above.
Notes:
- The interpreter matters.
dumper/extract_mapping.pylocates LLDB's Python bindings by matching the running interpreter's version against the installed LLVM, souv's bundled Python will fail to find them. Hence the explicit--python /opt/homebrew/bin/python3. protobuf<4is required for this step only.dumper/protodump.pyuses Protobuf internals that were removed in version 4; it is imported lazily, so recompiling the checked-in protos (previous section) works with any supportedprotobuf.- The app path may differ depending on the Keynote version installed
(e.g.
/Applications/Keynote 2025.app). Check your/Applicationsfolder. - The script briefly launches Keynote under the debugger to extract the type registry. Keynote may appear on screen momentarily — this is expected.
- No codesigning certificate is required: the script uses a local signing identity
if one is available and falls back to ad-hoc signing (
-) otherwise. - The generated files (
keynote_parser/versions/v*/generated/) are not committed to the repository and must be regenerated locally after cloning.
Troubleshooting
Unable to complete installation due to snappy-c.h not found.
snappy/snappymodule.cc:31:10: fatal error: 'snappy-c.h' file not found
This means you're missing the Snappy libraries. Install Snappy via whatever method your OS supports. e.g. brew install snappy, sudo apt-get install libsnappy-dev, etc.
Credits
keynote-parser was built by Peter Sobot but heavily based on prior
work by Sean Patrick O'Brien.
A copy of O'Brien's format documentation is included in the docs folder for posterity.
License
All code in this repository is licensed under the MIT License.
Copyright 2019-2025 Peter Sobot
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file keynote_parser-1.14.5.0.tar.gz.
File metadata
- Download URL: keynote_parser-1.14.5.0.tar.gz
- Upload date:
- Size: 380.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
10cb1c24156c6506a91d42fd023b1405c6bd6ebf22be4ef29ca028dd25162dd4
|
|
| MD5 |
aba901d144bc6fe3fee1142ed4377ea0
|
|
| BLAKE2b-256 |
df22ee6525d8ff68920fa19c2f8cdb27081060f7c2d529f97a31e6385f56e383
|
File details
Details for the file keynote_parser-1.14.5.0-py3-none-any.whl.
File metadata
- Download URL: keynote_parser-1.14.5.0-py3-none-any.whl
- Upload date:
- Size: 422.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bbbc39e91f5b0fd54b9181e55dcf4a7a787b5ec2aa71553472d40525d668cd48
|
|
| MD5 |
711c2f3f1287999a7478dfdcb400a16b
|
|
| BLAKE2b-256 |
dc16ba707670a0755e12062153a790d66e41649ad2c145aee73b737e252aba62
|