Skip to main content

Parser and analysis for WhatsApp chats exported as .txt files

Project description

whatsapp-chat-analyzer

Test PyPI Python License: MIT

Robust parser for WhatsApp chats exported as .txt files, with automatic format detection, clean data models and export to JSON, CSV and pandas.

The library is meant to be used in two ways: as a solid foundation to build custom analyses on top of (it hands you tidy Python objects), and as a ready-to-use tool thanks to the exporters and a small CLI.

Features

  • Automatic format detection: iOS and Android, DD/MM or MM/DD dates, 2- or 4-digit years, 24h or 12h time with AM/PM. The format can also be forced.
  • Typed messages: every message is classified as TEXT, MEDIA, SYSTEM or DELETED, with media subtype detection (image, video, audio, ...). The patterns are multilingual (Italian and English).
  • Multi-line messages handled correctly.
  • Parse-time transformations: date/author/system filters and name anonymization.
  • Analysis: per-user statistics, temporal activity (by hour/weekday/date) and content analysis (word frequencies and emoji usage).
  • Export: JSON (with re-import for round-tripping), CSV and pandas.DataFrame.
  • CLI wa-analyzer to convert a chat without writing code.
  • Zero required dependencies (standard library only); pandas is optional.

Installation

pip install whatsapp-chat-analyzer

For pandas.DataFrame export:

pip install whatsapp-chat-analyzer[pandas]

Requirements: Python 3.10+.

Quick start

from whatsapp_analyzer import parse_file

chat = parse_file("export.txt")

print(len(chat), "messages")
print("Participants:", chat.participants)

for msg in chat:
    print(msg.timestamp, msg.sender, "->", msg.text)

If you already have the content in memory (for example loaded from an upload):

from whatsapp_analyzer import parse_string

chat = parse_string(chat_text)

How to export a chat

Export it from your phone without media: Chat settings → More → Export chat → Without media. You will get a .txt file. The library automatically handles the utf-8 BOM that WhatsApp adds to some exports.

The data models

Chat

It behaves like a sequence of Message objects (supports len(), indexing and iteration) and offers a few conveniences:

chat.participants            # set of authors (system messages excluded)
chat.filter(predicate)       # new Chat with only the messages matching the predicate
chat.to_json()               # -> str (see the Export section)
chat.to_csv()                # -> str
chat.to_dataframe()          # -> pandas.DataFrame (requires the pandas extra)
Chat.from_json(data)         # rebuild a Chat from a JSON export

Message

It is an immutable object (frozen dataclass) with these fields:

Field Type Notes
timestamp datetime message date and time
sender str | None None for system messages (no author)
text str message body (multi-line ones include the \n)
type MessageType TEXT, MEDIA, SYSTEM, DELETED
media_kind MediaKind | None set only when type == MEDIA

MediaKind can be IMAGE, VIDEO, AUDIO, DOCUMENT, STICKER, GIF.

from whatsapp_analyzer import MessageType

text = [m for m in chat if m.type == MessageType.TEXT]
media = [m for m in chat if m.type == MessageType.MEDIA]

Configuration

All options go through ParserConfig, which also acts as a dependency injection point: if a field is left as None, the parser uses the default implementation.

from whatsapp_analyzer import parse_file, ParserConfig

config = ParserConfig(
    locale="it",                 # tie-break for ambiguous dates (DD/MM vs MM/DD)
    max_lines_per_message=1000,  # safeguard against corrupted files
    transformers=[],             # filters/anonymization (see below)
)

chat = parse_file("export.txt", config=config)

Available fields:

  • chat_format: force a specific format and skip automatic detection.
  • detectors: list of custom FormatDetectors (default: iOS + Android).
  • locale: used to disambiguate dates when the day is ≤ 12 in both positions. With "us"/"en_us" month-first is assumed, otherwise day-first.
  • classifier: an alternative MessageClassifier.
  • transformers: list of transformations applied in order (see below).
  • max_lines_per_message: beyond this threshold a message is truncated and a warning is emitted (protects against corrupted exports where the header is no longer recognized).

Forcing the format

If you have an export with a format the automatic detection does not catch, you can describe it by hand:

import re
from whatsapp_analyzer import parse_file, ParserConfig
from whatsapp_analyzer.detection.base import ChatFormat

fmt = ChatFormat(
    header_regex=re.compile(
        r"^(?P<date>\d{2}/\d{2}/\d{4}), (?P<time>\d{2}:\d{2}) - "
        r"(?:(?P<sender>[^:]+): )?(?P<text>.*)$"
    ),
    datetime_format="%d/%m/%Y, %H:%M",
)

chat = parse_file("export.txt", ParserConfig(chat_format=fmt))

Filters and anonymization

transformers are applied to every message in the order you put them in the list. Each one can modify the message or drop it.

from datetime import datetime
from whatsapp_analyzer import parse_file, ParserConfig
from whatsapp_analyzer.transform.filters import (
    DateRangeFilter, AuthorFilter, SystemMessageFilter,
)
from whatsapp_analyzer.transform.anonymizer import Anonymizer

config = ParserConfig(transformers=[
    SystemMessageFilter(),                       # drop system messages
    DateRangeFilter(start=datetime(2024, 1, 1)), # only from 2024 onwards
    AuthorFilter(["Mario"], mode="include"),     # only Mario's messages
    Anonymizer(),                                # Mario -> User1, Luigi -> User2, ...
])

chat = parse_file("export.txt", config=config)

Notes:

  • Order matters. As a rule of thumb, filter first and anonymize last.
  • AuthorFilter accepts mode="include" or mode="exclude".
  • Anonymizer replaces only the sender field with a stable alias for the whole chat; it does not touch the message text.

Analysis

The library ships three analyzers. Each one takes a Chat and returns an immutable report; the Chat shortcuts are the easiest way in.

chat = parse_file("export.txt")

# Per-user and overall statistics
stats = chat.statistics()
print(stats.message_count, "messages,", stats.system_count, "system")
for sender, user in stats.per_user.items():
    print(sender, user.message_count, user.word_count, user.media_count)

# Temporal activity
activity = chat.activity()
print("Most active hour:", activity.most_active_hour)
print("Messages on Mondays:", activity.by_weekday.get(0, 0))   # Monday == 0

# Content: word frequencies and emoji
content = chat.content(stopwords={"the", "a", "and"})
print(content.top_words(10))    # [("hello", 42), ...]
print(content.top_emojis(5))    # [("😂", 17), ...]

statistics() exposes ChatStatistics (message_count, system_count, first_timestamp, last_timestamp and a per_user map of UserStats). activity() returns an ActivityReport with by_hour, by_weekday, by_date maps plus most_active_hour/most_active_weekday. content() returns a ContentReport whose top_words(n) and top_emojis(n) give the most frequent items; word matching is Unicode-aware, lowercased, and ignores numbers, punctuation and non-text messages.

Each analyzer can also be used directly (for example with a custom configuration):

from whatsapp_analyzer import ContentAnalyzer

report = ContentAnalyzer(stopwords={"the", "a"}).analyze(chat)

Export

chat = parse_file("export.txt")

# JSON (timestamps in ISO 8601, enums as strings)
json_text = chat.to_json()

# Round-trip: reload without re-parsing the .txt
from whatsapp_analyzer import Chat
chat2 = Chat.from_json(json_text)

# CSV (one row per message)
csv_text = chat.to_csv()

# pandas (requires the [pandas] extra)
df = chat.to_dataframe()

The CSV and DataFrame columns are: timestamp, sender, text, type, media_kind.

CLI

After installation the wa-analyzer command is available:

# JSON to stdout
wa-analyzer export.txt --to json

# CSV to a file, dropping system messages and anonymizing authors
wa-analyzer export.txt --to csv --out chat.csv --no-system --anonymize

Options:

Flag Description
--to {json,csv} export format (default: json)
--out PATH output file (default: stdout)
--anonymize replace author names
--no-system drop system messages

Extending the library

The architecture is meant to be extended without touching the existing code:

  • new format → implement a FormatDetector and pass it in ParserConfig(detectors=...);
  • new transformation → extend MessageTransformer;
  • new export → extend Exporter;
  • new analysis → extend Analyzer.

Example of a custom transformer:

from dataclasses import replace
from whatsapp_analyzer.models import Message
from whatsapp_analyzer.transform.base import MessageTransformer

class UppercaseTransformer(MessageTransformer):
    def apply(self, msg: Message) -> Message | None:
        return replace(msg, text=msg.text.upper())

License

MIT.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

whatsapp_chat_analyzer-0.2.0.tar.gz (22.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

whatsapp_chat_analyzer-0.2.0-py3-none-any.whl (23.4 kB view details)

Uploaded Python 3

File details

Details for the file whatsapp_chat_analyzer-0.2.0.tar.gz.

File metadata

  • Download URL: whatsapp_chat_analyzer-0.2.0.tar.gz
  • Upload date:
  • Size: 22.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for whatsapp_chat_analyzer-0.2.0.tar.gz
Algorithm Hash digest
SHA256 dea57f1f25e39a1b625596f3a2d6b016273bf7d34faa47ea3b873b8dd95fd117
MD5 0ffe94f43c28bd225b832c00d6877277
BLAKE2b-256 3fced6fa6d68ee359f04d2dc292e4affe0456a5f3141d57826d4986ce44f9c8e

See more details on using hashes here.

Provenance

The following attestation bundles were made for whatsapp_chat_analyzer-0.2.0.tar.gz:

Publisher: publish.yml on mtmxo/whatsapp-chat-analyzer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file whatsapp_chat_analyzer-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for whatsapp_chat_analyzer-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f8ec7ed08b099a9d88663a15ea5ae7cbd37d91a4080b9355006e60390fc169b2
MD5 eb4bf1e084106e4a9c3cefab204edcc3
BLAKE2b-256 4c068ab81c15841b61b6561b85ce91bdc9ec54c868f0a5a4a3d3f01c7f7ce9cb

See more details on using hashes here.

Provenance

The following attestation bundles were made for whatsapp_chat_analyzer-0.2.0-py3-none-any.whl:

Publisher: publish.yml on mtmxo/whatsapp-chat-analyzer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page