WhatsApp

Search query language

Look up WhatsApp search fields, operators and time filters, with exact command examples.

If you use an AI agent with wa, you do not need to learn this language: describe what you want in plain words and the agent writes the query. This page is for people who type searches themselves, and for anyone who wants every filter: exact operators, every field, presets, date rules and limits.

It is the reference for the queries of wa personal search messages, wa personal search all, wa personal stats messages show and saved searches. For everyday examples start with search.

Terms used on this page:

  • Query: the text you search for, for example invoice from:me date:7d.
  • Field: a name and a colon that limit one part of the query to one property of a message, such as from: (the sender) or date: (when it was sent). Words without a field search the message text.
  • Operator: a word or sign that joins conditions, such as AND, OR and NOT.
  • Word forms: the same word with different endings. piso and pisos are forms of one word.

The language is shared by every WireCat CLI. It is a strict profile of Apache Lucene's query syntax: words, phrases, AND/OR/NOT, groups, fields, ranges, bounded wildcards and regular expressions. "Strict" means that anything it does not support is an error, never silently ignored. The full reference (in Russian) has the generated tables of fields, operators, presets and limits, and executable examples.

What it can do

You wantWrite
messages with all of these words, in any forminvoice paid
these words together, in this order"invoice paid"
one word or another, without a third(cafe OR library) NOT loud
only this exact form of a wordexact:piso, or --exact for every word without a field
words that start with somethinginvo*
a sender, a chat, a kind of chatfrom:me, chat:"Book club", kind:private
a perioddate:7d, date:[2026-01-01 TO 2026-02-01}
text that looks like a password, card or phonepreset:secret, preset:card
your own labelstag:work
a patterntext:/pass(port)?/

Words and phrases without a field match word forms. --exact selects exact forms for words without a field; an explicit text: still matches forms. The store's language settings decide which forms match (word forms).

Operators

OperatorExampleMeaning
wordsinvoice paidboth words
phrase"invoice paid"the words in this order
AND, &&alpha AND betaboth
OR, ||alpha OR betaeither
NOT, !, -alpha NOT betathe first without the second
++alpha OR betaalpha required, beta optional
group(alpha OR beta) gammabrackets set the order
field groupfrom:(alice OR bob)the field applies to each value
rangedate:[2026-01-01 TO 2026-02-01}[ ] include, { } exclude, * open
comparisondate>=7d, date:>=7dan open range; the colon form is the same
wildcardinvo*, te?t* any characters, ? one
regextext:/pass(port)?/a bounded Lucene regular expression

alpha OR beta gamma means (alpha OR beta) AND gamma; alpha OR beta AND gamma means alpha OR (beta AND gamma). Use brackets for clarity. Lowercase and, or, not are plain words. A query with only NOT finds nothing: give a positive condition, for example kind:group NOT preset:secret. Fuzzy ~, proximity, boosts and intervals are refused with an error, not ignored. Typos are not corrected: to catch several endings, use a wildcard such as invo*.

Fields

FieldFindsExample
textwords of the message (the default field)text:invoice
exactthe exact word or phrase formexact:piso, exact:"invoice paid"
bodythe whole original text, case-sensitivebody:/.*invoice.*/
fromthe sender, by name or id; me is youfrom:"Alice Synthetic", from:"100000000000001@lid"
chatthe chat, by name or idchat:"Book club", chat:[email protected]
datewhen it was sentdate:today, date:7d, date:[2026-01-01 TO 2026-02-01}
kindthe kind of chat: private, group, channel, saved and the shared restkind:private
haslink, and the file kinds of the shared languagehas:link
inwhich accounts: a providerin:whatsapp
presettext shaped like a secret or a contact detailpreset:secret
tagyour own local tag on the message, its chat or its sendertag:work
phonea phone number found in the text, however it is writtenphone:"<phone>"
emailan e-mail address found in the textemail:"[email protected]"
urla link found in the text, without tracking parametersurl:"https://example.com/a"
domainthe site of a link or an address found in the textdomain:example.com
mentionsa person, organization or document that a found mention is linked tomentions:"person:12"

Field names are case-sensitive. An unknown field, value or combination is an error, never an empty answer and never plain text. A name that the store does not know is not looked up on WhatsApp.

On WhatsApp, kind:private is a one-to-one chat, kind:group a group, kind:saved the chat with yourself and kind:channel a WhatsApp channel. Quote an id: @ is an operator. The file fields — content, filename, mime, size, and has: with file, photo, voice and the other attachment kinds — match the files of messages stored since wa handled files; content: needs the file's text read first (file attachments). topic: has nothing to match: WhatsApp has no forum topics.

Mentions

wa finds phones, e-mail addresses, links, documents and people's names in stored messages. Use these fields to find the messages that hold them. The finds themselves are listed by wa personal mentions list. To find a phone, first write the number to number.txt, on one line.

wa personal search messages "phone:\"$(cat number.txt)\""
wa personal search messages 'email:"[email protected]" OR domain:example.com'
wa personal search messages 'mentions:"person:12"'

In the table, <phone> stands for the number: these pages show no real one. Quote a value that has + or @, since both are operators. A phone is found however it is written: with or without spaces, dashes and the country code, it is one phone, and a number without + is read with the countries of the phone_countries setting. domain: treats docs.example.com as example.com. mentions: takes the reference of a person, an organization or a document, and finds the messages whose mentions you linked to it with wa personal mentions confirm.

Presets

A preset finds text by its shape. Use it to find a password, a code or a card number that someone sent.

PresetA candidate is
passworda password label followed by a value
codea verification-code label and 4–8 digits
api-keyan API-key label and a value
secreta password, secret, token or API-key label and a value
card13–19 digits with optional spaces or hyphens
bankan IBAN-shaped value
passporta labelled passport value or a Russian 4+6 digit shape
phonea plus-prefixed international phone shape
emailan email-address shape
urlan HTTP(S) link
contacta contact attachment, or an email or phone
locationa location attachment or a geo: link

A preset reports a candidate by its shape. It does not verify a password, a card or a document, and it can match something harmless. Do not delete or forward messages automatically on its word.

Dates

--timezone takes an IANA zone such as Europe/Madrid; without it, the computer's zone is used and returned in the answer. A date without a time is a whole calendar day. An inclusive upper day includes that whole day, an exclusive one excludes it; a day when clocks change can last 23 or 25 hours.

date:today and date:yesterday are calendar days. date:7d means from 7 days ago until now (also 30m, 2h); date>=7d and date:[30d TO 7d} work in comparisons and ranges, counted from the moment the query runs. An exact time is quoted, with seconds and an offset: date>="2026-01-01T10:00:00+02:00".

Words, wildcards and regular expressions

Text is folded before it is indexed and searched: lower case, without accents. A side effect: some different words become the same, such as año and ano. text: regular expressions and wildcards are folded the same way.

text:/pay/ matches the whole word pay, not payment. body:/pay/ matches only a message whose entire text is pay, case-sensitive; to find it anywhere use body:/.*pay.*/. This is Lucene's regular-expression syntax, without JavaScript lookaround, backreferences, anchors or flags.

On a large store a short prefix such as a* can expand to more than 10,000 words and is refused; lengthen it. Long queries, deep nesting, large patterns and slow scans are refused with validation_error, reason query.too-large, not cut short: narrow the chat, the dates or the pattern.

The answer

--json returns { items, page: { limit, has_more }, next?, missing?, meta }, even when nothing matched. --jsonl streams the items only.

  • items: the hits, best first (or newest first with --newest), each with its ref (msg:…), timestamp, sender_name, excerpt and matched_in.
  • meta.accounts: which accounts were searched.
  • missing: what the answer could not see, each with the step that fills it. text means the word index is still being built (step store.migrate, wa personal store migrate).
  • next: the steps to run. page.next repeats the query for the next page.
  • page.has_more is about the page, not about whether the phone holds more.

An error carries the position of the problem in the query and a hint.

Over MCP

When an agent searches through wa's MCP server, wa_read (command: "search messages") takes the query as query, and timezone for the calendar zone. chat takes an id or a stored name; source, newest, context and limit work as the command options do; saved runs a saved search. thread, thread_hops, thread_messages, thread_bytes and thread_within match the --thread… options. The answer has the same fields as --json. wa_read (command: "stats messages show") counts the same queries. wa personal mcp --no-record, or record set to false, keeps the server's calls out of the query history (MCP).

Next

  • Search: everyday searches, saved searches and counting.
  • The local store: what the store holds, and why a search may not see a message.