Skip to main content

whatsapp2pdf

CI PyPI License: MIT

A streaming Python library and CLI that turns a WhatsApp exported conversation into a familiar bubble-style PDF, including exported media. Everything runs locally: nothing is uploaded.

Documentation: https://jasalguero.github.io/whatsapp2pdf/

Cover page Chat page

Each PDF opens with a cover page (title, date range, participants and totals), then the chat on the familiar beige background: a date pill whenever the day changes, bubbles sized to their text, a tinted bubble and name color per sender, inline photos, and large emoji for emoji-only messages. (The screenshots come from a made-up chat; see scripts/make_demo.py.)

Export a chat

  • Android: open the chat, tap ⋮ → More → Export chat, then pick Include media or Without media.
  • iPhone: open the chat, tap its name → Export Chat, then pick Attach Media or Without Media.

Pass the resulting .zip (or .txt) to whatsapp2pdf. You don't need to unzip it. See the export guide for details.

Why it handles large exports

  • The chat text is parsed one message at a time rather than loaded into memory.
  • ZIP media is opened directly and only when its message is rendered; the ZIP is never bulk-extracted.
  • Images are resized individually before embedding.
  • ReportLab writes compressed PDF pages incrementally.

This makes multi-gigabyte ZIPs practical, although runtime and final PDF size still depend on the number and resolution of images. Python's zipfile needs the ZIP central directory in memory, which is proportional to the number of members, not their combined byte size.

Install

pipx install whatsapp2pdf   # or: pip install whatsapp2pdf

Requires Python 3.10 or newer.

CLI

whatsapp2pdf "WhatsApp Chat.zip" conversation.pdf \
  --me "Jane Doe" \
  --title "Family chat" \
  --font-size 10 \
  --bubble-width 0.70

Without --title, the title comes from the export's file name ("WhatsApp Chat - Family chat.zip" becomes "Family chat"). Other options:

  • --plain uses a white page background for cheaper printing.
  • --no-cover skips the cover page.
  • --emoji-font PATH points at a color emoji font when the system one isn't found.
  • --page-size A4|A5|A6, --font-size, --margin and --bubble-width adjust the layout.
  • --month-first reads ambiguous dates such as 03/04/26 as month/day.
  • --font / --bold-font take TrueType fonts for scripts Noto Sans doesn't cover.

If the archive contains several text files, the largest is used as the chat. Override it with --chat-member.

Python API

from whatsapp2pdf import LayoutConfig, PageSize, Theme, convert

layout = LayoutConfig(
    page_size=PageSize.A5,
    font_size=10,
    margin=32,
    max_bubble_width_ratio=0.68,
    media_max_height=180,
    theme=Theme(page="#EFEAE2", outgoing="#D9FDD3"),
)

result = convert(
    "WhatsApp Chat.zip",
    "conversation.pdf",
    outgoing={"Jane Doe", "Jane"},
    title="Family chat",
    config=layout,
)
print(result.messages)

The default page layout is A4. Choose A5 or A6 from the CLI with --page-size:

whatsapp2pdf export.zip conversation-a5.pdf --me "Jane Doe" --page-size A5
whatsapp2pdf export.zip conversation-a6.pdf --me "Jane Doe" --page-size A6

The Python API accepts either the enum (PageSize.A4, PageSize.A5, or PageSize.A6) or the corresponding string. Custom (width, height) tuples remain supported.

Text uses Noto Sans, bundled with the package (SIL Open Font License, see src/whatsapp2pdf/fonts/OFL.txt), so every machine produces the same PDF. Emoji are rendered from an installed color-emoji font when available (Apple Color Emoji on macOS, Noto Color Emoji on Linux, Segoe UI Emoji on Windows, or --emoji-font). For other non-Latin scripts, provide a suitable TrueType font via font_path and bold_font_path (or --font / --bold-font). Videos, audio, contacts, and documents are represented as attachment cards with font-independent vector icons; common image formats are embedded as previews.

Supported export forms

  • Android and iOS timestamp prefixes
  • Localized iOS a.m. / p.m. timestamps and invisible direction markers
  • 12-hour and 24-hour clocks
  • Day-first and month-first dates
  • Multiline messages and system messages
  • <attached: filename> and filename (file attached) media markers
  • ZIP exports and unpacked .txt exports with sibling media

Privacy and security

Conversion happens entirely on your machine, with no network access. Exports are treated as untrusted input: nothing is extracted to disk, media is looked up by bare file name inside the ZIP, and oversized or unexpected image formats are skipped. Please report vulnerabilities privately, as described in SECURITY.md.

Development

pip install -e '.[test]'
pytest

See CONTRIBUTING.md. Please never commit or attach real chat exports.

License

MIT, see LICENSE. The bundled Noto Sans fonts are licensed under the SIL Open Font License 1.1 (src/whatsapp2pdf/fonts/OFL.txt). Emoji glyphs in generated PDFs come from your system's emoji font and remain under that font's license. See NOTICE.

This project is not affiliated with WhatsApp or Meta. "WhatsApp" is a trademark of WhatsApp LLC.

Metadata

Release files for whatsapp2pdf 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for whatsapp2pdf 0.1.0
File Size Uploaded
whatsapp2pdf-0.1.0.tar.gz 658.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for whatsapp2pdf 0.1.0
File Interpreter ABI Platform
whatsapp2pdf-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 1.3 MB

Release files / whatsapp2pdf-0.1.0.tar.gz

Download URL whatsapp2pdf-0.1.0.tar.gz
Size 658.5 kB
Tags Source
SHA-256 checksum
How to use checksums
63894af8a679035d3669b449cbf4fb9a184243e22e518247ae4a79d80be166ae
BLAKE2b-256 checksum
How to use checksums
9f1ca4dd37cdeb754e81d1cf046c576b3dd315ca3c7f7ae4f5e6891fd238163a
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 Oct 11, 2026.

Transparency log

Release files / whatsapp2pdf-0.1.0-py3-none-any.whl

Download URL whatsapp2pdf-0.1.0-py3-none-any.whl
Size 662.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4cb9c94a9c12ec82a0b5df723607b201803d03f1f42573f95f333b3dc9d35ab8
BLAKE2b-256 checksum
How to use checksums
703b26a0437b93fea3b1aa999e4c0258268ce6e16badf52607770c9e90a92ac5
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 Oct 11, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page