Skip to content

Capturing Network Traffic (pcap)

pymobiledevice3 pcap records every packet an iPhone or iPad sends and receives, on every interface (Wi-Fi, cellular, VPN, loopback), and labels each packet with the process that sent or received it. It needs no jailbreak, no Developer Mode, no Xcode and no Mac, and runs the same on macOS, Linux and Windows. It uses the device's built-in pcapd service, the same one behind Apple's macOS-only rvictl.

$ pymobiledevice3 pcap --process com.apple.WebKit -c 3
2026-11-05 09:31:54.113152: Process com.apple.WebKit (730), Interface: en0 (ethernetCsmacd), Family: AF_INET
00000000: 02 00 00 00 00 01 02 00  00 00 00 02 08 00 45 00  ..............E.
00000010: 00 40 00 00 40 00 40 06  49 D3 C0 A8 32 D5 8C 52  .@..@.@.I...2..R
00000020: 71 15 D8 AE 01 BB BF 0B  07 75 00 00 00 00 B0 C2  q........u......
00000030: FF FF 06 5E 00 00 02 04  05 B4 01 03 03 06 01 01  ...^............
00000040: 08 0A 4D 27 50 E7 00 00  00 00 04 02 00 00        ..M'P.........
​
2026-11-05 09:31:54.256712: Process com.apple.WebKit (730), Interface: en0 (ethernetCsmacd), Family: AF_INET
00000000: 02 00 00 00 00 01 02 00  00 00 00 02 08 00 45 00  ..............E.
00000010: 00 3C 00 00 40 00 25 06  64 D7 8C 52 71 15 C0 A8  .<..@.%.d..Rq...
00000020: 32 D5 01 BB D8 AE E3 FB  09 20 BF 0B 07 76 A0 52  2........ ...v.R
00000030: FF FF 70 C4 00 00 02 04  05 9C 04 02 08 0A 23 92  ..p...........#.
00000040: 96 73 4D 27 50 E7 01 03  03 0A                    .sM'P.....
​
2026-11-05 09:31:54.257935: Process com.apple.WebKit (730), Interface: en0 (ethernetCsmacd), Family: AF_INET
00000000: 02 00 00 00 00 01 02 00  00 00 00 02 08 00 45 00  ..............E.
00000010: 00 34 00 00 40 00 40 06  49 DF C0 A8 32 D5 8C 52  .4..@.@.I...2..R
00000020: 71 15 D8 AE 01 BB BF 0B  07 76 E3 FB 09 21 80 10  q........v...!..
00000030: 08 16 97 15 00 00 01 01  08 0A 4D 27 51 77 23 92  ..........M'Qw#.
00000040: 96 73                                             .s

Quick start

Connect the device over USB, unlock it and trust the computer, then:

pymobiledevice3 pcap --out capture.pcapng

Use the device, press Ctrl+C to stop, and open capture.pcapng in Wireshark. While capturing, each packet is also printed to the terminal (a one-line summary plus a hex dump); without --out, that terminal output is all you get.

The file is always pcapng

The output is written in the pcapng format whatever extension you give it, because pcapng is what carries the per-packet process labels. Name it .pcapng so every tool recognizes it.

Filtering while you capture

Option Keeps only packets... Example
--process NAME_OR_PID owned by this process (exact name, or PID) --process MobileSafari
-i, --interface NAME on this interface (en0), or on all units of one (en) -i en0
-c, --count N ...and stops after N of them -c 200

The options combine:

# The first 200 Wi-Fi packets of Safari
pymobiledevice3 pcap --process MobileSafari -i en0 -c 200 --out safari.pcapng
  • Process names are the executable names the kernel reports (as pymobiledevice3 processes ps shows them), not the app's display name, and are truncated to 16 characters. Matching is exact and case-sensitive. A PID only matches while that process runs, so the name is usually the better choice.
  • Interfaces you will typically see: en0 (Wi-Fi), pdp_ip0 and friends (cellular), utun0... (VPNs and system tunnels), lo0 (loopback). Capture without -i first to see which ones carry traffic on your device.

Which process sent this packet?

Every packet in the file carries a comment like:

PID: 312, ProcName: nsurlsessiond, EPID: 1045, EProcName: MyApp, SVC: 0
  • ProcName / PID is the process that owns the socket.
  • EProcName / EPID is the effective process: the one the traffic is really for. iOS often lets a system daemon do networking on an app's behalf (for example nsurlsessiond for background transfers). Then ProcName is the daemon and EProcName is the app. For ordinary traffic both name the same process.

--process matches ProcName only. To find everything an app caused, including work delegated to daemons, capture without --process and filter on EProcName afterwards.

In Wireshark

Wireshark shows the comment under Packet comments in the packet details. Right-click it and choose Apply as Column to see the process next to every packet. Display filters:

frame.comment contains "EProcName: MyApp,"
frame.comment matches "^PID: [0-9]+, ProcName: MobileSafari,"

The first keeps everything done for MyApp; the second keeps only packets whose socket MobileSafari itself owns. The trailing comma stops MyApp from also matching MyAppExtension.

With tshark

tshark (Wireshark's command-line tool) can answer the common questions directly:

# Packets per effective process, busiest first
tshark -r capture.pcapng -T fields -e frame.comment \
  | sed -E 's/.*EProcName: ([^,]*),.*/\1/' | sort | uniq -c | sort -rn

# Which hosts did each process connect to over TLS (from the SNI)
tshark -r capture.pcapng -Y tls.handshake.extensions_server_name \
  -T fields -e frame.comment -e tls.handshake.extensions_server_name

# DNS lookups and who asked for them
tshark -r capture.pcapng -Y "dns.flags.response == 0" -T fields -e frame.comment -e dns.qry.name

Live capture in Wireshark

On macOS and Linux, point Wireshark at a named pipe and let pymobiledevice3 write into it:

mkfifo /tmp/ios.pcapng
wireshark -k -i /tmp/ios.pcapng &
pymobiledevice3 pcap --out /tmp/ios.pcapng > /dev/null

Packets appear in Wireshark as they arrive (> /dev/null silences the terminal copy). On macOS, wireshark is /Applications/Wireshark.app/Contents/MacOS/Wireshark unless you installed the command-line wrapper.

What a capture shows

  • Encrypted traffic (HTTPS, QUIC, most app traffic) shows its endpoints, sizes, timing and the TLS server name, not its contents. DNS queries are usually readable.
  • Packets from interfaces without an Ethernet header (cellular, VPN, loopback) get a placeholder Ethernet header with the address be:ef:be:ef:be:ef so every pcap tool can open the file. That address is not real hardware.
  • The capture includes everything on the device, possibly personal data. Treat capture files as sensitive.

From Python

import asyncio

from pymobiledevice3.lockdown import create_using_usbmux
from pymobiledevice3.services.pcapd import PcapdService


async def main():
    async with await create_using_usbmux() as lockdown, PcapdService(lockdown) as pcap:
        async for packet in pcap.watch(packets_count=20):
            print(packet.comm, packet.ecomm, packet.interface_name, len(packet.data))

        # Or write a pcapng file, with the same filters as the CLI
        with open("capture.pcapng", "wb") as out:
            await pcap.write_to_pcap(out, pcap.watch(packets_count=100, process="MobileSafari"))


asyncio.run(main())

See the PcapdService reference for every field of a captured packet.