Summary
WhatsApp Business is a separate Android app with its own package folder, com.whatsapp.w4b. A report built only from the standard WhatsApp artifacts does not open that folder. This contribution adds nine artifacts that read it, and it is also an example of how a contribution should describe what has not been checked.
- One new module,
WhatsAppBusiness.py, adds nine artifacts: contacts, call logs, legacy messages, one-to-one messages, group messages, group details, channels, channel messages and user profile. - Each one runs the WhatsApp artifact of the same name, with paths that match only
com.whatsapp.w4b. The two apps are read on their own and never mixed. - Status: In review. The pull request is open as a draft. On 25 October 2026 the maintainer asked for a run on real WhatsApp Business data before it can go in.
- No real Business store has been parsed yet. The pull request says so in its checklist, and each artifact repeats it in its notes.
- 9artifacts added
- 43files changed
- 1,640lines added
- 18synthetic cases
Methodology note
Drafted with AI assistance and reviewed by the author before publication. The pull request was also prepared with AI assistance, as its description states.
The issue
Picture an examiner with a full file system extraction of a phone used for a small shop. The shopkeeper talks to customers in WhatsApp Business, a different app from the one most people have. The examiner runs the parser and gets a WhatsApp section, or none. The Business chats are in the extraction, under com.whatsapp.w4b, but no artifact looks there. The absence in the report reads as absence on the phone, and it is neither.
The reverse risk is just as real. If a Business artifact matched paths loosely, a phone with both apps would show two apps' chats in one table, and an examiner could attribute a conversation to the wrong app. The two apps need separate stores, separate artifacts and a clear label.
An earlier attempt at the same idea, pull request #1499 by another contributor, was closed by the maintainer with change requests. This work uses the same wrapper approach, tries to answer each of those requests, and credits the idea to that pull request.
Show this figure as a table
| State | Folder | Read by |
|---|---|---|
| Before | com.whatsapp | WhatsApp artifacts (9) |
| Before | com.whatsapp.w4b | No artifact |
| With this change | com.whatsapp | WhatsApp artifacts (9) |
| With this change | com.whatsapp.w4b | WhatsApp Business artifacts (9) |
The essence
The module is a thin layer. Each Business artifact calls the existing WhatsApp artifact of the same name through __wrapped__, the way justalk.py already runs its Kids variants. Because the Business paths match only com.whatsapp.w4b, the shared code never sees a com.whatsapp file during a Business run.
One supporting change moved the profile code in WhatsApp.py into _user_profile_rows, so the Business profile can match its own preference file names. The output of WhatsApp - User Profile is unchanged. A second change lets the test harness record a wrapper's shared implementation.
| Artifact | Reads (under com.whatsapp.w4b) | Note in the artifact |
|---|---|---|
| WhatsApp Business - Contacts | databases/wa.db | Channel and status@broadcast jids left out, as in WhatsApp |
| WhatsApp Business - Call Logs | msgstore.db, wa.db | LID jids resolved through jid_map |
| WhatsApp Business - Messages | msgstore.db, wa.db | Legacy schema with messages.data only |
| WhatsApp Business - One To One Messages | msgstore.db, wa.db, media folders | Modern schema; media folder location assumed |
| WhatsApp Business - Group Messages | msgstore.db, wa.db, media folders | Modern schema; media folder location assumed |
| WhatsApp Business - Group Details | msgstore.db, wa.db, files/Avatars | Avatars folder assumed |
| WhatsApp Business - Channels | msgstore.db | Newsletter table assumed to be the same |
| WhatsApp Business - Channel Messages | msgstore.db, media folders | Media folder location assumed |
| WhatsApp Business - User Profile | shared_prefs files ending preferences_light.xml, startup_prefs.xml, or named com.whatsapp.w4b_preferences.xml | Five keys; file name not verified on a device |
Our methodology
The method here is mostly about limits. We could not read a real Business store, so the work is designed to show exactly how far the evidence goes.
Keep the two apps apart. A new test file, test_whatsapp_business.py, lists the files of a device that holds both apps and checks that every Business artifact matches only Business files and that no WhatsApp artifact matches a Business file. It also checks that every WhatsApp artifact has a Business twin, that the conversation views stay equal to the WhatsApp ones, and that each function is its own artifact processor. A run test builds synthetic databases for both packages and reads them.
Show the shared code did not change. The refactored WhatsApp.py was run against upstream on three real WhatsApp extractions and every WhatsApp output file was byte-identical. The Business artifacts were then run on copies of two real WhatsApp databases placed under com.whatsapp.w4b, and gave the same row counts and identical output bodies, paths aside. This shows the wrapper reads the same schema in the same way. It does not show the Business app uses that schema, and the pull request says so.
Record what fails. A comparison run with a second copy of the data reads one store, not two, because the WhatsApp code reads only the first msgstore.db and wa.db it is given. The nine Business legs of that test are recorded as known failures; the fix belongs in the shared code.
Say what is assumed. Every note ends with a validation boundary. The media folder, the avatar folder, the preference file name and the channels table are listed as assumed. After review, the profile match was widened to also accept com.whatsapp.w4b_preferences.xml, a name taken from a vendor's published acquisition guide. That is a second-hand description of an extraction, and the note says so.
Fix review findings. Two User Profile baselines were first recorded on Windows with backslash paths and would fail on macOS and on the Linux runner. They were re-recorded with forward slashes and now pass the repository runner.
Show this figure as a table
| Check | Result | Shows |
|---|---|---|
| Refactored WhatsApp.py vs upstream main, 3 extractions | Every WhatsApp TSV byte-identical | Shared code unchanged |
| Business artifacts on relabelled copies of 2 real WhatsApp databases | Same row counts; TSV bodies byte-identical (paths aside) | Wrapper reads the same schema the same way |
| Business artifacts on a real Business extraction | Not done; none available | Would show whether the Business app uses that schema |
The value
For an examiner the value is a route to a store that was invisible. If a phone carries com.whatsapp.w4b, the report can list the Business conversations, calls, groups, channels and profile values in their own category. It can answer a plain question: does this device hold a Business store, and what does the shared reader return from it?
The limit is just as important. Until the code has run on a real Business store, the rows are indicators to be verified against the app or another source. The pull request is built so that the report itself carries that warning in every artifact's notes. We think that is the right default for an app nobody on the project could test.
What is pending. The maintainer asked for a known data extraction: WhatsApp Business installed on a test phone or a rooted emulator with a test account, a few messages, a call, a group, a channel and a profile, then a full file system extraction, with counts added to sample_data. The author replied that no such extraction exists yet and asked for the pull request to be marked as a draft until one does. A public dataset on WhatsApp Business was checked and does not help: it is an unrooted quick image with no Business databases or preferences. The baseline fix was pushed and awaits the repository checks. Continuous integration runs for first-time contributors need a maintainer's approval, so none had run when the pull request was written.
None of this makes the artifacts wrong. It means the claim stays narrow, and it keeps a reviewer from having to trust an app we could not test.
Show this figure as a table
| Item | Named in app package (strings) | Run on constructed data | Seen in a real Business store |
|---|---|---|---|
| msgstore.db and wa.db | Names only | Yes | No |
| Preferences file and keys | Partly (startup_prefs) | Yes | No |
| Media folder | Not listed | Yes | No |
| Avatars folder | Name only | Yes | No |
| Channels table | Fields only | Yes | No |
Where this sits in the Lab's research
No Lab report covers this yet; the method above is from the pull request. It is a case of recording a negative result: a contribution that states, in the code and in the report, what has not been validated. The Lab's other posts in this series show the same checks (synthetic fixtures, independent recounts, behavior on missing data) applied to artifacts that did have real data.
Sources
| Claim or number | Where it comes from |
|---|---|
| Nine artifacts and their names | PR body (What this changes); diff, scripts/artifacts/WhatsAppBusiness.py |
Wrapper through __wrapped__; paths match only com.whatsapp.w4b | PR body; diff, WhatsAppBusiness.py (functions and paths) |
| 1,640 lines added, 6 removed, 43 files changed, 4 commits | PR metadata (gh pr view, 5 November 2026) |
Profile code moved into _user_profile_rows; output unchanged | PR body; diff, scripts/artifacts/WhatsApp.py |
| 18 synthetic cases; run_test_cases PASS=150 (132 on upstream plus 18) | PR body (Test record); diff, admin/test/cases/testdata.WhatsAppBusiness.json |
| 6 new tests in test_whatsapp_business.py | PR body (Test record: 1,582 tests on the branch against 1,576 on upstream) |
| Four Samsung Android 16 extractions, none with com.whatsapp.w4b | PR body (checklist: unverified on real data); maintainer review |
| Real WhatsApp comparison: three extractions, TSVs byte-identical; two databases relabelled, same counts | PR body (checklist) |
| Second-copy comparison reads one store; nine known-failure legs | PR body (checklist); diff, admin/test/cases/known_failures.json |
| Changes requested 25 October 2026; baselines with backslash paths | PR reviews (maintainer) |
| Baselines fixed; no real extraction available; public dataset checked; draft requested | PR comments (author, 25 October 2026) |
| Preference file name from a vendor guide; not verified | PR comments; diff notes of get_whatsapp_business_user_profile |
| Earlier pull request #1499 closed with change requests | PR body (Prior work) |
| Open as a draft; no activity after 25 October 2026 | PR metadata (isDraft, updatedAt) |
| No Lab report covers this | Lab report inventory (no paper maps to this pull request) |